Initial Import from SVN

This commit is contained in:
Matt Jenkins
2014-04-09 14:27:18 +01:00
parent 8976e834c4
commit 895f96d2f7
3153 changed files with 748589 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
#
# Copyright (c) 1980 Regents of the University of California.
# All rights reserved. The Berkeley software License Agreement
# specifies the terms and conditions for redistribution.
#
TOPSRC = $(shell cd ..; pwd)
include $(TOPSRC)/target.mk
# Programs that live in subdirectories, and have makefiles of their own.
#
SUBDIR = startup-$(MACHINE) libc libm libutil libtermlib libcurses \
libvmf libwiznet share cmd games
all: $(SUBDIR)
$(SUBDIR): FRC
$(MAKE) -C $@
FRC:
install: elf32-mips.ld
-for i in $(SUBDIR); do \
$(MAKE) -C $$i DESTDIR=$(DESTDIR) all install; done
# cp -p elf32-mips.ld $(DESTDIR)/lib/elf32-mips.ld
clean:
rm -f a.out core *.s *.o *.a *~
-for i in $(SUBDIR); do $(MAKE) -C $$i clean; done
+127
View File
@@ -0,0 +1,127 @@
#
# Copyright (c) 1980 Regents of the University of California.
# All rights reserved. The Berkeley software License Agreement
# specifies the terms and conditions for redistribution.
#
TOPSRC = $(shell cd ../..; pwd)
include $(TOPSRC)/target.mk
CFLAGS += -Werror
# Programs that live in subdirectories, and have makefiles of their own.
# /bin
SUBDIR = adb adc-demo ar as awk basic cc chflags chpass \
cpp dc diff env fdisk find forth fstat glcdtest hostname \
id la lcc lcpp ld ls login make man med \
more nm passwd picoc portio printf pwm \
rdprof ranlib re renice retroforth scm setty sl \
sed sh smallc smlrc stty sysctl test uname wiznet xargs \
zmodem gtest msec unixbench cron compress date2 tip \
talloc devupdate uucp smux
# /sbin
SUBDIR += chown chroot disktool fsck getty init \
mkfs mknod mkpasswd mount pstat \
reboot shutdown umount update vipw virus
# TODO: ccom lex m4 yacc reloc sre pforth
# Shell scripts that need only be installed and are never removed.
#
SCRIPT = false nohup true #lorder mkdep
# C programs that live in the current directory and do not need
# explicit make lines.
#
STD = basename cal cat cb chgrp chmod cmp col comm cp dd du \
echo ed fgrep file grep head hostid join kill last ln \
mesg mkdir mv nice od pagesize pr printenv pwd rev rm rmail rmdir \
size sleep sort split sum sync tail tar tee time touch tr \
tsort tty uniq w wc whereis who
# C programs that live in the current directory and need explicit make lines.
#
NSTD = bc expr egrep
# Programs that must run setuid to root
#
SETUID = mail su
# Programs that run set-group-id operator
#
OPERATOR = df
# Programs that must run set-group-id kmem.
#
KMEM = ps iostat vmstat
# Programs that must run set-group-id tty.
#
TTY = wall write
# 'strip' is handled specially because 'install -s' now uses 'strip' and
# thus we can't do a 'install -s strip /bin/strip' without an error.
#
BINS = $(STD) $(NSTD) $(SETUID) $(OPERATOR) $(KMEM) $(TTY) $(SCRIPT) strip
all: $(SUBDIR) $(BINS)
$(SUBDIR): FRC
$(MAKE) -C $@ $(MFLAGS)
FRC:
# $(STD) $(SETUID) $(KMEM) $(OPERATOR) $(TTY) strip
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@.elf $< $(LIBS)
$(OBJDUMP) -S $@.elf > $@.dis
$(SIZE) $@.elf
$(ELF2AOUT) $@.elf $@ && /bin/rm $@.elf
# Files listed in $(NSTD) have explicit make lines given below.
# bc egrep expr
%.c: %.y
$(YACC) $(YFLAGS) $<
-/bin/mv y.tab.c $@
$(SCRIPT):
install -c $@.sh $@
install: $(BINS)
install $(STD) $(NSTD) strip $(DESTDIR)/bin/
-for i in $(SUBDIR); do \
$(MAKE) -C $$i $(MFLAGS) DESTDIR=$(DESTDIR) install; done
-for i in $(SCRIPT); do install $$i.sh $(DESTDIR)/bin/$$i; done
-for i in $(SETUID); do \
install -m 4751 $$i $(DESTDIR)/bin/$$i; done
-for i in $(OPERATOR); do \
install -m 2751 $$i $(DESTDIR)/bin/$$i; done
-for i in $(KMEM); do \
install -m 2751 $$i $(DESTDIR)/bin/$$i; done
-for i in $(TTY); do \
install -m 2751 $$i $(DESTDIR)/bin/$$i; done
clean:
/bin/rm -f $(BINS) expr.c a.out core *.s *.o *.dis *.elf *~ y.tab.c errs
for i in $(SUBDIR); do (cd $$i; $(MAKE) $(MFLAGS) clean); done
depend: expr.c
for i in $(BINS); do \
cc -M $(INCPATH) $$i.c | sed 's/\.o//' | \
awk ' ( if ($$1 != prev) \
( if (rec != "") print rec; rec = $$0; prev = $$1; ) \
else ( if (length(rec $$2) > 78) ( print rec; rec = $$0; ) \
else rec = rec " " $$2 ) ) \
END ( print rec ) ' >> makedep; done
echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ed - Makefile < eddep
/bin/rm eddep makedep
echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
echo '# see make depend above' >> Makefile
# DO NOT DELETE THIS LINE -- make depend uses it
+24
View File
@@ -0,0 +1,24 @@
#
# Public domain - 1996/10/26 - sms
#
TOPSRC = $(shell cd ..; pwd)
include $(TOPSRC)/target.mk
SUBDIR = chown-src chroot-src disktool-src fsck-src getty-src init-src \
mkfs-src mknod-src mkpasswd-src mount-src pstat-src \
reboot-src shutdown-src umount-src update-src vipw-src
all: ${SUBDIR}
${SUBDIR}: FRC
cd $@; make ${MFLAGS} all
FRC:
install: FRC
-for i in ${SUBDIR}; do \
(cd $$i; make ${MFLAGS} DESTDIR=${DESTDIR} install); done
clean:
for i in ${SUBDIR}; do (cd $$i; make ${MFLAGS} clean); done
rm -f *~
+26
View File
@@ -0,0 +1,26 @@
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
#CFLAGS = -DCROSS -I$(TOPSRC)/include -I/usr/include -D__mips__ -ggdb3
OBJS = message.o access.o command.o expr.o findfn.o format.o input.o \
main.o opset.o output.o pcs.o print.o \
runpcs.o setup.o sym.o
CFLAGS += -DNUM_SYMS_CACHE=50 -Wall -Werror
all: adb
adb: $(OBJS)
${CC} ${LDFLAGS} -o adb.elf $(OBJS) ${LIBS}
${OBJDUMP} -S adb.elf > adb.dis
${SIZE} adb.elf
${ELF2AOUT} adb.elf $@ && rm adb.elf
clean:
rm -f *.o *.0 *.elf adb *.elf *.dis tags *~
install: all
install adb $(DESTDIR)/bin/
$(OBJS): defs.h
+73
View File
@@ -0,0 +1,73 @@
The makefile can be adjusted to make a version of adb for
nonseparate I/D machines. Change the -DNUM_VM_PAGES value to
something like 6 to 8, this will use less real memory (and cause
adb to run a bit slower) and allow adb to run on a non-split I/D
machine.
Changes for overlaid processes are intended to work in the most obvious way
and are:
1. There is an additional map for an overlay (430 or 431) object
file, described by the triple (bo,eo,fo). bo is initialized
on startup, and the others are changed on setting an overlay.
This is done automatically if there is an appropriate corefile
or when a traced subprocess stops, and can be done manually
(described below).
2. There are two additional internal variables set for overlay objects.
The variable o is the sum of the overlay sizes. c is the current
overlay number. It is set automatically as described above,
and can be changed manually (#>c). This changes the overlay
map (eo and fo) to map in the named overlay. This affects only
adb's mapping.
3. Although the variable c controls the overlay map, the "register"
variable "ov" reflects the overlay actually mapped when the
process stopped (or dumped core). This value is shown as "ov"
in the register list ($r). It may also be used as other register
variables, in the "<" and ">" commands. In the latter case,
this actually causes the kernel to remap the subprocess, and the
correct overlay must be mapped to restart the process. NOTE:
the kernel routine procxmt must support overlay changes for this
to work. The (1982) 2bsd distribution includes the necessary
changes.
4. For text symbols in overlaid objects, the default symbol
used to find "name" is "~name" rather than "_name". This
means that the actual subroutine, rather than its thunk, is
found. To examine a thunk, use "_name" explicitly.
5. In the overlaid segment, only symbols in the current overlay
(c) are used in symbolic addresses. In order to find these
overlay numbers, the new version of (ov)ld must be used.
The reason for this is that the previous version of ovld put
the overlay number only in symbols for thunks,
not in local text symbols.
6. In order to support breakpoints in overlaid segments, the
strategy used by adb has been changed slightly. Breakpoints
are written into the subprocess immediately when a ":b"
command is executed, and deleted immediately with ":d".
Changes to support overlaid kernels:
1. The user's saved registers are in different places in the
kernel stack. They are found relative to the entry u.u_ar0
in the core file if there is one, with offsets from <sys/reg.h>
and <sys/user.h>. If there is no core file,a default is
used. This default is defined as UAR0 in defs.h.
******* UAR0 should be checked whenever the user structure changes.
2. There is a new command-line flag, -k, which sets things
appropriately for the kernel.
It sets the mapping of the core file appropriately
for 407, 411 and 430 kernels, and changes the debugger's idea of
saved register locations. Thus, $r will print the register
values saved by dump, and $c will use the saved r5 from low core.
In addition, a number of minor bugs have been fixed.
Mike Karels
ucbvax!virus!mike
Department of Molecular Biology
University of California, Berkeley
+130
View File
@@ -0,0 +1,130 @@
/*
* File handling and access routines
*/
#include "defs.h"
#include <fcntl.h>
static int
within(adr, lbd, ubd)
long adr, lbd, ubd;
{
return (adr>=lbd && adr<ubd);
}
static int
chkmap(adr, space)
register long *adr;
register int space;
{
register MAPPTR amap;
amap = (space & DSP) ? &datmap : &txtmap;
switch (space & (ISP | DSP | STAR)) {
case ISP:
if (within(*adr, amap->b1, amap->e1)) {
*adr += (amap->f1) - (amap->b1);
break;
}
/* falls through */
case ISP+STAR:
if (within(*adr, amap->b2, amap->e2)) {
*adr += (amap->f2) - (amap->b2);
break;
}
goto err;
case DSP:
if (within(*adr, amap->b1, amap->e1)) {
*adr += (amap->f1) - (amap->b1);
break;
}
/* falls through */
case DSP+STAR:
if (within(*adr, amap->b2, amap->e2)) {
*adr += (amap->f2) - (amap->b2);
break;
}
/* falls through */
default:
err: errflg = (space & DSP) ? BADDAT : BADTXT;
return 0;
}
return 1;
}
int
acces(mode, adr, space, value)
long adr;
{
int w, w1, pmode, rd, file;
BKPTR bkptr;
if (space == NSP)
return 0;
rd = (mode == RD);
if (pid) { /* tracing on? */
if ((adr & 3) && ! rd)
error(ODDADR);
pmode = (space & DSP) ?
(rd ? PT_READ_D : PT_WRITE_D) :
(rd ? PT_READ_I : PT_WRITE_I);
bkptr = scanbkpt((u_int) adr);
if (bkptr) {
if (rd)
return bkptr->ins;
bkptr->ins = value;
return 0;
}
w = ptrace(pmode, pid, (void*) shorten(adr & ~1), value);
if (adr & 01) {
w1 = ptrace(pmode, pid, (void*) shorten(adr + 1), value);
w = ((w >> 8) & LOBYTE) | (w1 << 8);
}
if (errno) {
errflg = (space & DSP) ? BADDAT : BADTXT;
}
return w;
}
w = 0;
if (mode==WT && wtflag==O_RDONLY) {
error("not in write mode");
}
if (! chkmap(&adr, space))
return 0;
file = (space & DSP) ? datmap.ufd : txtmap.ufd;
if (lseek(file, adr, 0) == -1L ||
(rd ? read(file, &w, 4) : write(file, &value, 4)) < 1) {
errflg = (space & DSP) ? BADDAT : BADTXT;
}
return w;
}
void
put(adr, space, value)
long adr;
{
acces(WT, adr, space, value);
}
u_int
get(adr, space)
long adr;
{
return acces(RD, adr, space, 0);
}
u_int
chkget(n, space)
long n;
{
register int w;
w = get(n, space);
chkerr();
return w;
}
+239
View File
@@ -0,0 +1,239 @@
/*
* Command decoding
*/
#include "defs.h"
int lastcom = '=';
static char eqformat[512] = "o";
static char stformat[512] = "o\"= \"^i";
static long locval;
static long locmsk;
int
command(buf, defcom)
char *buf;
int defcom;
{
int itype, ptype, modifier, regptr;
char longpr, eqcom;
char wformat[1];
char savc;
long w, savdot;
char *savlp=lp;
if (buf) {
if (*buf == EOR)
return(FALSE);
lp = buf;
}
do {
adrflg = expr(0);
if (adrflg) {
dot = expv;
ditto = dot;
}
adrval = dot;
if (rdc()==',' && expr(0)) {
cntflg = TRUE;
cntval = expv;
} else {
cntflg = FALSE;
cntval = 1;
lp--;
}
if (! eol(rdc())) {
lastcom = lastc;
} else {
if (adrflg == 0) {
dot = inkdot(dotinc);
}
lp--;
lastcom = defcom;
}
switch (lastcom & STRIP) {
case '/':
itype = DSP;
ptype = DSYM;
goto trystar;
case '=':
itype = NSP;
ptype = ASYM;
goto trypr;
case '?':
itype = ISP;
ptype = ISYM;
goto trystar;
trystar:
if (rdc() == '*') {
lastcom |= QUOTE;
} else {
lp--;
}
if (lastcom & QUOTE) {
itype |= STAR;
ptype = (DSYM + ISYM) - ptype;
}
trypr:
longpr = FALSE;
eqcom = (lastcom == '=');
switch (rdc()) {
case 'm': { /* reset map data */
int fcount;
MAPPTR smap;
long *mp;
if (eqcom) {
error(BADEQ);
}
smap = (itype & DSP) ? &datmap : &txtmap;
fcount = 3;
if (itype & STAR) {
mp = &(smap->b2);
} else {
mp = &(smap->b1);
}
while (fcount-- && expr(0)) {
*(mp)++ = expv;
}
if (rdc() == '?') {
smap->ufd = fsym;
} else if (lastc == '/') {
smap->ufd = fcor;
} else {
lp--;
}
}
break;
case 'L':
longpr = TRUE;
case 'l': /* search for exp */
if (eqcom) {
error(BADEQ);
}
dotinc = 2;
savdot = dot;
expr(1);
locval = expv;
if (expr(0)) {
locmsk = expv;
} else {
locmsk = -1L;
}
for (;;) {
w = leng(get(dot, itype));
if (longpr) {
//w = itol(w, get(inkdot(2), itype));
}
if (errflg || mkfault || (w & locmsk) == locval)
break;
dot = inkdot(dotinc);
}
if (errflg) {
dot = savdot;
errflg = NOMATCH;
}
psymoff(dot, ptype, "");
break;
case 'W':
longpr = TRUE;
case 'w':
if (eqcom) {
error(BADEQ);
}
wformat[0] = lastc;
expr(1);
do {
savdot = dot;
psymoff(dot, ptype, ":%16t");
exform(1, wformat, itype, ptype);
errflg = 0;
dot = savdot;
if (longpr) {
put(dot, itype, expv);
}
put((longpr ? inkdot(2) : dot), itype, shorten(expv));
savdot = dot;
print("=%8t");
exform(1, wformat, itype, ptype);
printc(EOR);
} while (expr(0) && errflg == 0);
dot = savdot;
chkerr();
break;
default:
lp--;
getformat(eqcom ? eqformat : stformat);
if (! eqcom) {
if (*stformat != 'a') {
psymoff(dot, ptype, ":%16t");
}
}
scanform(cntval, (eqcom ? eqformat : stformat), itype, ptype);
}
break;
case '>':
lastcom = 0;
savc = rdc();
regptr = getreg(savc);
if (regptr != NOREG) {
uframe[regptr] = shorten(dot);
ptrace(PT_WRITE_U, pid, (char*) (KERNEL_DATA_END - USIZE) +
((char*)&uframe[regptr] - (char*)&corhdr),
uframe[regptr]);
} else if ((modifier = varchk(savc)) != -1) {
var[modifier] = dot;
} else {
error(BADVAR);
}
break;
case '!':
lastcom = 0;
unox();
break;
case '$':
lastcom = 0;
printtrace(nextchar());
break;
case ':':
if (! executing) {
executing = TRUE;
subpcs(nextchar());
executing = FALSE;
lastcom = 0;
}
break;
case 0:
print("%s\n", myname);
break;
default:
error(BADCOM);
}
flushbuf();
} while (rdc() == ';');
if (buf) {
lp = savlp;
} else {
lp--;
}
return (adrflg && dot != 0);
}
+55
View File
@@ -0,0 +1,55 @@
TOPSRC = $(shell cd ../../../..; pwd)
include $(TOPSRC)/cross.mk
vpath %.c ..
# Build a list of the host include directories.
CPP = $(shell gcc -print-prog-name=cc1)
HOSTINC = $(addprefix -I,$(shell echo | $(CPP) -v 2>&1 | grep '^ /.*include'))
HOSTINC += -I/usr/include/i386-linux-gnu
CFLAGS = -m32 -g -DCROSS -nostdinc -I. $(HOSTINC) -I.. -D__mips__
CFLAGS += -Wall -Werror -DNUM_SYMS_CACHE=50 -fno-builtin
LDFLAGS += -m32 -g
OBJS = message.o access.o command.o expr.o findfn.o format.o input.o \
main.o opset.o output.o pcs.o print.o \
runpcs.o setup.o sym.o
HEADERS = a.out.h nlist.h time.h signal.h stdlib.h \
sys/exec.h sys/types.h sys/param.h sys/user.h \
sys/time.h sys/dir.h sys/resource.h sys/select.h \
sys/signal.h sys/wait.h \
machine/io.h machine/machparam.h
all: $(HEADERS) adb
adb: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o $@
clean:
rm -f *~ *.o adb *.h */*.h gccdump.s
$(HEADERS):
ln -s -f ../../../../include/a.out.h .
ln -s -f ../../../../include/nlist.h .
ln -s -f ../../../../include/time.h .
ln -s -f ../../../../include/stdlib.h .
ln -s -f sys/signal.h .
ln -s -f ../../../../../include/sys/exec.h sys/
ln -s -f ../../../../../include/sys/param.h sys/
ln -s -f ../../../../../include/sys/user.h sys/
ln -s -f ../../../../../include/sys/types.h sys/
ln -s -f ../../../../../include/sys/time.h sys/
ln -s -f ../../../../../include/sys/dir.h sys/
ln -s -f ../../../../../include/sys/resource.h sys/
ln -s -f ../../../../../include/sys/select.h sys/
ln -s -f ../../../../../include/sys/wait.h sys/
ln -s -f ../../../../../include/sys/signal.h sys/
ln -s -f ../../../../../include/machine/io.h machine/
ln -s -f ../../../../../include/machine/machparam.h machine/
test:
echo '$$q' | ./adb fsck fsck.core
@printf '\n----------------------------\n'
echo '$$m' | ./adb fsck fsck.core
@printf '\n----------------------------\n'
+303
View File
@@ -0,0 +1,303 @@
/*
* UNIX debugger - common definitions
*
* 1998/4/21 - remove local redefinitions used with ptrace
*
* Layout of a.out file (fsym):
*
* This has changed over time - see a.out.h, sys/exec.h and nlist.h
* for the current a.out definition and format.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/user.h>
#include <machine/io.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <a.out.h>
#include <sys/ptrace.h>
#ifdef CROSS
# include <termios.h>
# define sgttyb termios
#else
# include <sgtty.h>
#endif
#define MAXSYMLEN 32
#define MAXCOM 64
#define MAXARG 32
#define LINSIZ 512
#define LPRMODE "%Q"
#define OFFMODE "+%x"
/*
* This is the memory resident portion of a symbol. The only difference
* between this and a 'nlist' entry is the size of the string offset By
* restricting the string table to be less than 64kb we save 2 bytes per
* symbol - approximately 7.5kb of D space in the case of /unix's symbol
* table. In practice this restriction is unlikely to be reached since
* even the kernel's symbol table of ~28kb only has a strings table of 21kb.
*/
struct SYMbol {
u_int value;
u_int type;
char *sname;
};
#define SYMTYPE(symflag) (( symflag>=041 || (symflag>=02 && symflag<=04))\
? ((symflag&07)>=3 ? DSYM : (symflag&07))\
: NSYM)
typedef struct map MAP;
typedef MAP *MAPPTR;
typedef struct bkpt BKPT;
typedef BKPT *BKPTR;
/* file address maps */
struct map {
long b1; /* text base address */
long e1; /* text end address */
long f1; /* file start to text offset */
long b2; /* data base address */
long e2; /* data end address */
long f2; /* file start to data offset */
int ufd;
};
struct bkpt {
int loc;
int ins;
int count;
int initcnt;
char flag;
char comm[MAXCOM];
BKPT *nxtbkpt;
};
struct reglist {
char *rname;
int roffs;
};
typedef struct reglist REGLIST;
/*
* Internal variables ---
* They are addressed by name. (e.g. (`0'-`9', `a'-`b'))
* thus there can only be 36 of them.
*/
#define VARB 11
#define VARC 12 /* current overlay number */
#define VARD 13
#define VARE 14
#define VARM 22
#define VARO 24 /* overlay text segment addition */
#define VARS 28
#define VART 29
#define RD 0
#define WT 1
#define NSP 0
#define ISP 1
#define DSP 2
#define STAR 4
#define DSYM 7
#define ISYM 2
#define ASYM 1
#define NSYM 0
#define ESYM 0177
#define BKPTSET 1
#define BKPTEXEC 2
#define BPT 03
#define NOREG 32767 /* impossible return from getreg() */
#define NREG FRAME_WORDS
/*
* UFRAME is the value used for subprocesses when there is no core file.
*/
#define UFRAME (&corhdr[1]) /* default address of r0 (u.u_frame) */
#define KR0 (0300/2) /* location of r0 in kernel dump */
#define KR1 (KR0+1)
#define KR2 (KR0+2)
#define KR3 (KR0+3)
#define KR4 (KR0+4)
#define KR5 (KR0+5)
#define KSP (KR0+6)
#define KA6 (KR0+7) /* saved ka6 in kernel dump */
#define MAXOFF 255
#define MAXPOS 80
#define MAXLIN 128
#ifndef TRUE
#define TRUE (-1)
#endif
#define FALSE 0
#define LOBYTE 0377
#define HIBYTE 0177400
#define STRIP 0177
#define SP ' '
#define TB '\t'
#define EOR '\n'
#define QUOTE 0200
#define ALIGNED (~3)
/* long to ints and back (puns) */
#define leng(a) ((long)((unsigned)(a)))
#define shorten(a) ((long)a)
struct sgttyb adbtty, usrtty;
jmp_buf erradb;
sig_t sigint, sigqit;
MAP txtmap;
MAP datmap;
BKPTR bkpthead; /* breakpoints */
struct SYMbol *symbol;
extern u_int *uframe;
const char *errflg;
char *lp;
char *myname; /* program name */
char *printptr;
extern char *Ipath;
extern char *symfil;
extern char *corfil;
char printbuf[MAXLIN];
int wtflag;
int pid;
int executing;
int fcor;
int fsym;
int mkfault;
int dotinc;
int adrflg;
int cntflg;
int lastframe;
int kernel;
int callpc;
int octal;
int localok;
int maxoff;
int maxpos;
int eof;
int infile;
int argcount;
int magic;
int signo;
extern int lastc;
extern int lastcom;
extern int outfile;
long dot;
long ditto;
long expv;
long adrval;
long cntval;
long localval;
long maxfile;
long txtsiz;
long datsiz;
long datbas;
long stksiz;
long entrypt;
long loopcnt;
long var[36];
u_int corhdr [USIZE/sizeof(u_int)];
off_t symoff;
extern const REGLIST reglist [];
extern const char BADMOD[];
extern const char BADCOM[];
extern const char BADSYM[];
extern const char BADLOC[];
extern const char NOCFN[];
extern const char NOMATCH[];
extern const char NOBKPT[];
extern const char BADKET[];
extern const char NOADR[];
extern const char NOPCS[];
extern const char BADVAR[];
extern const char BADTXT[];
extern const char BADDAT[];
extern const char ODDADR[];
extern const char EXBKPT[];
extern const char A68BAD[];
extern const char A68LNK[];
extern const char ADWRAP[];
extern const char BADEQ[];
extern const char BADWAIT[];
extern const char ENDPCS[];
extern const char NOFORK[];
extern const char BADSYN[];
extern const char NOEOR[];
extern const char SZBKPT[];
extern const char LONGFIL[];
extern const char NOTOPEN[];
extern const char TOODEEP[];
struct SYMbol *cache_by_string (char *);
struct SYMbol *symget (void);
char *exform (int, char *, int, int);
void error (const char *);
long inkdot (int);
BKPTR scanbkpt (int);
char *cache_sym (struct SYMbol *);
char *no_cache_sym (struct SYMbol *);
long roundn (long, long);
void chkerr (void);
int expr (int);
int eol (int);
int rdc (void);
u_int get (long, int);
void put (long, int, int);
void psymoff (long, int, char *);
void print (char *, ...);
void printc (int);
void getformat (char *);
void scanform (long, char *, int, int);
int getreg (int);
int varchk (int);
void unox (void);
void printtrace (int);
int nextchar (void);
void subpcs (int);
void flushbuf (void);
int readchar (void);
int findroutine (long);
int eqsym (char *, char *, int);
int localsym (long);
void symset (void);
int quotchar (void);
u_int chkget (long, int);
u_int findsym (u_int, int);
void endline (void);
void printins (int, unsigned, unsigned);
void iclose (int, int);
void oclose (void);
void setsym (void);
void setcor (void);
void delbp (void);
void done (void);
int command (char *, int);
void endpcs (void);
void del1bp (BKPTR);
void set1bp (BKPTR);
void setbp (void);
void setup (void);
int getsig (int);
int runpcs (int, int);
void printpc (void);
void sigprint (void);
void valpr (int, int);
void symINI (struct exec *);
+961
View File
@@ -0,0 +1,961 @@
.sp 100
.nr PS 9
.nr VS 11
. \" START OF Figures
.de P1
.nf
.in +.5i
.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i
.sp
.ps 9
.vs 11p
..
.de P2
.sp
.fi
.ps \\n(PS
.vs \\n(VS
.in -.5i
..
.SH
Figure 1: C program with pointer bug
.LP
.P1
struct buf {
int fildes;
int nleft;
char *nextp;
char buff[512];
}bb;
struct buf *obuf;
char *charp "this is a sentence.";
main(argc,argv)
int argc;
char **argv;
{
char cc;
if(argc < 2) {
printf("Input file missing\\n");
exit(8);
}
if((fcreat(argv[1],obuf)) < 0){
printf("%s : not found\\n", argv[1]);
exit(8);
}
charp = \'T\';
printf("debug 1 %s\\n",charp);
while(cc= *charp++)
putc(cc,obuf);
fflush(obuf);
}
.P2
.sp 100
.SH
Figure 2: ADB output for C program of Figure 1
.LP
.P1
.ft B
adb a.out core
$c
.ft R
~main(02,0177762)
.ft B
$C
.ft R
~main(02,0177762)
argc: 02
argv: 0177762
cc: 02124
.ft B
$r
.ft R
ps 0170010
pc 0204 ~main+0152
sp 0177740
r5 0177752
r4 01
r3 0
r2 0
r1 0
r0 0124
~main+0152: mov _obuf,(sp)
.ft B
$e
.ft R
savr5: 0
_obuf: 0
_charp: 0124
_errno: 0
_fout: 0
.ft B
$m
.ft R
text map \`ex1\'
b1 = 0 e1 = 02360 f1 = 020
b2 = 0 e2 = 02360 f2 = 020
data map \`core1\'
b1 = 0 e1 = 03500 f1 = 02000
b2 = 0175400 e2 = 0200000 f2 = 05500
.ft B
*charp/s
.ft R
0124: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTLx Nh@x&_
~
.ft B
charp/s
.ft R
_charp: T
_charp+02: this is a sentence.
_charp+026: Input file missing
.ft B
main.argc/d
.ft R
0177756: 2
.ft B
*main.argv/3o
.ft R
0177762: 0177770 0177776 0177777
.ft B
0177770/s
.ft R
0177770: a.out
.ft B
*main.argv/3o
.ft R
0177762: 0177770 0177776 0177777
.ft B
*"/s
.ft R
0177770: a.out
.ft B
.=o
.ft R
0177770
.ft B
.\(mi10/d
.ft R
0177756: 2
.ft B
$q
.P2
.sp 100
.SH
Figure 3: Multiple function C program for stack trace illustration
.LP
.P1
int fcnt,gcnt,hcnt;
h(x,y)
{
int hi; register int hr;
hi = x+1;
hr = x\(miy+1;
hcnt++ ;
hj:
f(hr,hi);
}
g(p,q)
{
int gi; register int gr;
gi = q\(mip;
gr = q\(mip+1;
gcnt++ ;
gj:
h(gr,gi);
}
f(a,b)
{
int fi; register int fr;
fi = a+2*b;
fr = a+b;
fcnt++ ;
fj:
g(fr,fi);
}
main()
{
f(1,1);
}
.P2
.sp 100
.SH
Figure 4: ADB output for C program of Figure 3
.LP
.P1
.ft B
adb
$c
.ft R
~h(04452,04451)
~g(04453,011124)
~f(02,04451)
~h(04450,04447)
~g(04451,011120)
~f(02,04447)
~h(04446,04445)
~g(04447,011114)
~f(02,04445)
~h(04444,04443)
.ft B
HIT DEL KEY
.ft R
adb
.ft B
,5$C
.ft R
~h(04452,04451)
x: 04452
y: 04451
hi: ?
~g(04453,011124)
p: 04453
q: 011124
gi: 04451
gr: ?
~f(02,04451)
a: 02
b: 04451
fi: 011124
fr: 04453
~h(04450,04447)
x: 04450
y: 04447
hi: 04451
hr: 02
~g(04451,011120)
p: 04451
q: 011120
gi: 04447
gr: 04450
.ft B
fcnt/d
.ft R
_fcnt: 1173
.ft B
gcnt/d
.ft R
_gcnt: 1173
.ft B
hcnt/d
.ft R
_hcnt: 1172
.ft B
h.x/d
.ft R
022004: 2346
.ft B
$q
.P2
.sp 100
.SH
Figure 5: C program to decode tabs
.LP
.P1
#define MAXLINE 80
#define YES 1
#define NO 0
#define TABSP 8
.sp .5
char input[] "data";
char ibuf[518];
int tabs[MAXLINE];
.sp .5
main()
{
int col, *ptab;
char c;
.sp .5
ptab = tabs;
settab(ptab); /*Set initial tab stops */
col = 1;
if(fopen(input,ibuf) < 0) {
printf("%s : not found\\n",input);
exit(8);
}
while((c = getc(ibuf)) != \(mi1) {
switch(c) {
case \(fm\\t\(fm: /* TAB */
while(tabpos(col) != YES) {
putchar(\(fm \(fm); /* put BLANK */
col++ ;
}
break;
case \(fm\\n\(fm: /*NEWLINE */
putchar(\(fm\\n\(fm);
col = 1;
break;
default:
putchar(c);
col++ ;
}
}
}
.sp .5
/* Tabpos return YES if col is a tab stop */
tabpos(col)
int col;
{
if(col > MAXLINE)
return(YES);
else
return(tabs[col]);
}
.sp .5
/* Settab - Set initial tab stops */
settab(tabp)
int *tabp;
{
int i;
.sp .5
for(i = 0; i<= MAXLINE; i++)
(i%TABSP) ? (tabs[i] = NO) : (tabs[i] = YES);
}
.P2
.sp 100
.SH
Figure 6a: ADB output for C program of Figure 5
.LP
.P1
.ft B
adb a.out \(mi
settab+4:b
fopen+4:b
getc+4:b
tabpos+4:b
$b
.ft R
breakpoints
count bkpt command
1 ~tabpos+04
1 _getc+04
1 _fopen+04
1 ~settab+04
.ft B
settab,5?ia
.ft R
~settab: jsr r5,csv
~settab+04: tst \(mi(sp)
~settab+06: clr 0177770(r5)
~settab+012: cmp $0120,0177770(r5)
~settab+020: blt ~settab+076
~settab+022:
.ft B
settab,5?i
.ft R
~settab: jsr r5,csv
tst \(mi(sp)
clr 0177770(r5)
cmp $0120,0177770(r5)
blt ~settab+076
.ft B
:r
.ft R
a.out: running
breakpoint ~settab+04: tst \(mi(sp)
.ft B
settab+4:d
:c
.ft R
a.out: running
breakpoint _fopen+04: mov 04(r5),nulstr+012
.ft B
$C
.ft R
_fopen(02302,02472)
~main(01,0177770)
col: 01
c: 0
ptab: 03500
.ft B
tabs,3/8o
.ft R
03500: 01 0 0 0 0 0 0 0
01 0 0 0 0 0 0 0
01 0 0 0 0 0 0 0
.P2
.sp 100
.SH
Figure 6b: ADB output for C program of Figure 5
.LP
.P1
.ft B
:c
.ft R
a.out: running
breakpoint _getc+04: mov 04(r5),r1
.ft B
ibuf+6/20c
.ft R
__cleanu+0202: This is a test of
.ft B
:c
.ft R
a.out: running
breakpoint ~tabpos+04: cmp $0120,04(r5)
.ft B
tabpos+4:d
settab+4:b settab,5?ia
settab+4:b settab,5?ia; 0
getc+4,3:b main.c?C; 0
settab+4:b settab,5?ia; ptab/o; 0
$b
.ft R
breakpoints
count bkpt command
1 ~tabpos+04
3 _getc+04 main.c?C;0
1 _fopen+04
1 ~settab+04 settab,5?ia;ptab?o;0
~settab: jsr r5,csv
~settab+04: bpt
~settab+06: clr 0177770(r5)
~settab+012: cmp $0120,0177770(r5)
~settab+020: blt ~settab+076
~settab+022:
0177766: 0177770
0177744: @\`
T0177744: T
h0177744: h
i0177744: i
s0177744: s
.P2
.sp 100
.SH
Figure 7: ADB output for C program with breakpoints
.LP
.in +.5i
.nf
.ps 8
.vs 9
.ft B
adb ex3 \(mi
h+4:b hcnt/d; h.hi/; h.hr/
g+4:b gcnt/d; g.gi/; g.gr/
f+4:b fcnt/d; f.fi/; f.fr/
:r
.ft R
ex3: running
_fcnt: 0
0177732: 214
symbol not found
.ft B
f+4:b fcnt/d; f.a/; f.b/; f.fi/
g+4:b gcnt/d; g.p/; g.q/; g.gi/
h+4:b hcnt/d; h.x/; h.y/; h.hi/
:c
.ft R
ex3: running
_fcnt: 0
0177746: 1
0177750: 1
0177732: 214
_gcnt: 0
0177726: 2
0177730: 3
0177712: 214
_hcnt: 0
0177706: 2
0177710: 1
0177672: 214
_fcnt: 1
0177666: 2
0177670: 3
0177652: 214
_gcnt: 1
0177646: 5
0177650: 8
0177632: 214
.ft B
HIT DEL
f+4:b fcnt/d; f.a/"a = "d; f.b/"b = "d; f.fi/"fi = "d
g+4:b gcnt/d; g.p/"p = "d; g.q/"q = "d; g.gi/"gi = "d
h+4:b hcnt/d; h.x/"x = "d; h.y/"h = "d; h.hi/"hi = "d
:r
.ft R
ex3: running
_fcnt: 0
0177746: a = 1
0177750: b = 1
0177732: fi = 214
_gcnt: 0
0177726: p = 2
0177730: q = 3
0177712: gi = 214
_hcnt: 0
0177706: x = 2
0177710: y = 1
0177672: hi = 214
_fcnt: 1
0177666: a = 2
0177670: b = 3
0177652: fi = 214
.ft B
HIT DEL
$q
.in -.5i
.sp 100
.SH
Figure 8: ADB address maps
.LP
.de l1
.tc
.ta 1.20i +1.6i +2.5i
..
.de l3
.tc
.ta 1.6i +2.80i +.2i +1.55i
..
.de l2
.tc
.ti 1.0i
.ta +0.5i +3.0i +1.75i
.tc _
..
.de l5
.tc
.ti 1.0i
.ta +0.75i +3.0i +1.5i
.tc _
..
.de l6
.tc
.ti 1.0i
.ta +.8i +2.85i +0.4i +1.1i
..
.de l8
.tc
.ti 1.0i
.ta +0.5i +3.0i +1.75i
.tc _
..
.de la
.tc
.ta 1.20i +1.25i +1.7i
..
.de lc
.tc
.ti 1.0i
.ta +.85i +1.6i +.35i +1.1i
..
.de lb
.tc
.ti 1.0i
.ta +0.75i +1.75i +1.5i
.tc _
..
.ul
407 files
.sp
.l1
a.out hdr text+data
.l2
| | |
.l3
0 D
.sp
.l1
core hdr text+data stack
.l5
| | ......| |
.l6
0 D S E
.sp 2
.ul
410 files (shared text)
.sp
.l1
a.out hdr text data
.l2
| | | |
.l3
0 T B D
.sp
.la
core hdr data stack
.lb
| | ......| |
.lc
B D S E
.sp 2
.ul
411 files (separated I and D space)
.sp
.l1
a.out hdr text data
.l2
| | | |
.l3
0 T 0 D
.sp
.la
core hdr data stack
.lb
| | ......| |
.lc
0 D S E
.sp 2
The following
.ul
adb
variables are set.
.nf
.ta .75i 1.5i 3.5i 4.5i 5.5i
.sp
407 410 411
.sp
b base of data 0 B 0
d length of data D D\(miB D
s length of stack S S S
t length of text 0 T T
.sp 100
.SH
Figure 9: ADB output for maps
.LP
.nf
.in +.5i
.ft B
adb map407 core407
$m
.ft R
text map \`map407\'
b1 = 0 e1 = 0256 f1 = 020
b2 = 0 e2 = 0256 f2 = 020
data map \`core407\'
b1 = 0 e1 = 0300 f1 = 02000
b2 = 0175400 e2 = 0200000 f2 = 02300
.ft B
$v
.ft R
variables
d = 0300
m = 0407
s = 02400
.ft B
$q
.sp 2
adb map410 core410
$m
.ft R
text map \`map410\'
b1 = 0 e1 = 0200 f1 = 020
b2 = 020000 e2 = 020116 f2 = 0220
data map \`core410\'
b1 = 020000 e1 = 020200 f1 = 02000
b2 = 0175400 e2 = 0200000 f2 = 02200
.ft B
$v
.ft R
variables
b = 020000
d = 0200
m = 0410
s = 02400
t = 0200
.ft B
$q
.sp 2
adb map411 core411
$m
.ft R
text map \`map411\'
b1 = 0 e1 = 0200 f1 = 020
b2 = 0 e2 = 0116 f2 = 0220
data map \`core411\'
b1 = 0 e1 = 0200 f1 = 02000
b2 = 0175400 e2 = 0200000 f2 = 02200
.ft B
$v
.ft R
variables
d = 0200
m = 0411
s = 02400
t = 0200
.ft B
$q
.in -.5i
.sp 100
.SH
Figure 10: Simple C program for illustrating formatting and patching
.LP
.P1
char str1[] "This is a character string";
int one 1;
int number 456;
long lnum 1234;
float fpt 1.25;
char str2[] "This is the second character string";
main()
{
one = 2;
}
.P2
.sp 100
.SH
Figure 11: ADB output illustrating fancy formats
.LP
.nf
.ps 9
.vs 11p
.ft B
adb map410 core410
<b,\(mi1/8ona
.ft R
020000: 0 064124 071551 064440 020163 020141 064143 071141
.sp .5
_str1+016: 061541 062564 020162 072163 064562 063556 0 02
.sp .5
_number:
_number: 0710 0 02322 040240 0 064124 071551 064440
.sp .5
_str2+06: 020163 064164 020145 062563 067543 062156 061440 060550
.sp .5
_str2+026: 060562 072143 071145 071440 071164 067151 0147 0
.sp .5
savr5+02: 0 0 0 0 0 0 0 0
.sp .5
.ft B
<b,20/4o4^8Cn
.ft R
020000: 0 064124 071551 064440 @\`@\`This i
020163 020141 064143 071141 s a char
061541 062564 020162 072163 acter st
064562 063556 0 02 ring@\`@\`@b@\`
.sp .5
_number: 0710 0 02322 040240 H@a@\`@\`R@d @@
0 064124 071551 064440 @\`@\`This i
020163 064164 020145 062563 s the se
067543 062156 061440 060550 cond cha
060562 072143 071145 071440 racter s
071164 067151 0147 0 tring@\`@\`@\`
0 0 0 0 @\`@\`@\`@\`@\`@\`@\`@\`
0 0 0 0 @\`@\`@\`@\`@\`@\`@\`@\`
data address not found
.ft B
<b,20/4o4^8t8cna
.ft R
020000: 0 064124 071551 064440 This i
_str1+06: 020163 020141 064143 071141 s a char
_str1+016: 061541 062564 020162 072163 acter st
_str1+026: 064562 063556 0 02 ring
_number:
_number: 0710 0 02322 040240 HR
_fpt+02: 0 064124 071551 064440 This i
_str2+06: 020163 064164 020145 062563 s the se
_str2+016: 067543 062156 061440 060550 cond cha
_str2+026: 060562 072143 071145 071440 racter s
_str2+036: 071164 067151 0147 0 tring
savr5+02: 0 0 0 0
savr5+012: 0 0 0 0
data address not found
.ft B
<b,10/2b8t^2cn
.ft R
020000: 0 0
.sp .5
_str1: 0124 0150 Th
0151 0163 is
040 0151 i
0163 040 s
0141 040 a
0143 0150 ch
0141 0162 ar
0141 0143 ac
0164 0145 te
.ft B
$Q
.sp 100
.SH
Figure 12: Directory and inode dumps
.LP
.nf
.ft B
adb dir \(mi
=nt"Inode"t"Name"
0,\(mi1?ut14cn
.ft R
Inode Name
0: 652 .
82 ..
5971 cap.c
5323 cap
0 pp
.sp 4
.ft B
adb /dev/src \(mi
.ft B
02000>b
?m<b
.ft R
new map \`/dev/src\'
b1 = 02000 e1 = 0100000000 f1 = 0
b2 = 0 e2 = 0 f2 = 0
.ft B
$v
.ft R
variables
b = 02000
.ft B
<b,\(mi1?"flags"8ton"links,uid,gid"8t3bn"size"8tbrdn"addr"8t8un"times"8t2Y2na
.ft R
02000: flags 073145
links,uid,gid 0163 0164 0141
size 0162 10356
addr 28770 8236 25956 27766 25455 8236 25956 25206
times 1976 Feb 5 08:34:56 1975 Dec 28 10:55:15
02040: flags 024555
links,uid,gid 012 0163 0164
size 0162 25461
addr 8308 30050 8294 25130 15216 26890 29806 10784
times 1976 Aug 17 12:16:51 1976 Aug 17 12:16:51
02100: flags 05173
links,uid,gid 011 0162 0145
size 0147 29545
addr 25972 8306 28265 8308 25642 15216 2314 25970
times 1977 Apr 2 08:58:01 1977 Feb 5 10:21:44
.\"
.\" Start of Summary
.sp 100
.TL
ADB Summary
.LP
.LP
.if t .2C
.nr VS 9
.nr VS 11
.SH
Command Summary
.LP
.ta .7i
a) formatted printing
.sp .5
.IP "\fB? \fIformat\fR" .7i
print from \fIa.out\fR file according to \fIformat\fR
.IP "\fB/ \fIformat\fR" .7i
print from \fIcore\fR file according to \fIformat\fR
.IP "\fB= \fIformat\fR" .7i
print the value of \fIdot\fR
.sp .5
.IP "\fB?w\fR expr" .7i
write expression into \fIa.out\fR file
.IP "\fB/w\fR expr" .7i
write expression into \fIcore\fR file
.sp .5
.IP "\fB?l\fR expr" .7i
locate expression in \fIa.out\fR file
.LP
.ta .7i
b) breakpoint and program control
.LP
.ta .7i
.nf
.ta .7i
\fB:b\fR set breakpoint at \fIdot\fR
\fB:c\fR continue running program
\fB:d\fR delete breakpoint
\fB:k\fR kill the program being debugged
\fB:r\fR run \fIa.out\fR file under ADB control
\fB:s\fR single step
.LP
.ta .7i
c) miscellaneous printing
.LP
.ta .7i
.nf
\fB$b\fR print current breakpoints
\fB$c\fR C stack trace
\fB$e\fR external variables
\fB$f\fR floating registers
\fB$m\fR print ADB segment maps
\fB$q\fR exit from ADB
\fB$r\fR general registers
\fB$s\fR set offset for symbol match
\fB$v\fR print ADB variables
\fB$w\fR set output line width
.LP
.ta .7i
d) calling the shell
.LP
.ta .7i
.nf
\fB!\fR call \fIshell\fP to read rest of line
.LP
.ta .7i
e) assignment to variables
.LP
.ta .7i
.nf
\fB>\fIname\fR assign dot to variable or register \fIname\fR
.sp 100
.SH
Format Summary
.LP
.ta .7i
.nf
\fBa \fRthe value of dot
\fBb \fRone byte in octal
\fBc \fRone byte as a character
\fBd \fRone word in decimal
\fBf \fRtwo words in floating point
\fBi \fRPDP 11 instruction
\fBo \fRone word in octal
\fBn \fRprint a newline
\fBr \fRprint a blank space
\fBs \fRa null terminated character string
\fIn\fBt \fRmove to next \fIn\fR space tab
\fBu \fRone word as unsigned integer
\fBx \fRhexadecimal
\fBY \fRdate
\fB^ \fRbackup dot
\fB"..."\fR print string
.LP
.ta .7i
.SH
Expression Summary
.LP
.ta .7i
a) expression components
.LP
.ta .1.1i
.nf
\fBdecimal integer \fRe.g. 256
\fBoctal integer \fRe.g. 0277
\fBhexadecimal \fRe.g. #ff
\fBsymbols \fRe.g. flag _main main.argc
\fBvariables \fRe.g. <b
\fBregisters \fRe.g. <pc <r0
\fB(expression) \fRexpression grouping
.LP
.ta .7i
b) dyadic operators
.LP
.ta .7i
.nf
\fB+\fP add
\fB\(mi\fP subtract
\fB*\fP multiply
\fB%\fP integer division
\fB&\fP bitwise and
\fB|\fP bitwise or
\fB#\fP round up to the next multiple
.LP
.ta .7i
c) monadic operators
.LP
.ta .7i
.nf
\v'.25m'\s+2\fB~\fP\s0\v'-.25m' not
\fB*\fR contents of location
\fB\(mi\fR integer negate
.fi
+527
View File
@@ -0,0 +1,527 @@
=== Figure 1: C program with pointer bug ===
<code c>
struct buf {
int fildes;
int nleft;
char *nextp;
char buff[512];
}bb;
struct buf *obuf;
char *charp "this is a sentence.";
main(argc,argv)
int argc;
char **argv;
{
char cc;
if(argc < 2) {
printf("Input file missing\n");
exit(8);
}
if((fcreat(argv[1],obuf)) < 0){
printf("%s : not found\n", argv[1]);
exit(8);
}
charp = 'T';
printf("debug 1 %s\n",charp);
while(cc= *charp++)
putc(cc,obuf);
fflush(obuf);
}
</code>
=== Figure 2: ADB output for C program of Figure 1 ===
**adb a.out core**
**$c**
~main(02,0177762)
**$C**
~main(02,0177762)
argc: 02
argv: 0177762
cc: 02124
**$r**
ps 0170010
pc 0204 ~main+0152
sp 0177740
r5 0177752
r4 01
r3 0
r2 0
r1 0
r0 0124
~main+0152: mov _obuf,(sp)
**$e**
savr5: 0
_obuf: 0
_charp: 0124
_errno: 0
_fout: 0
**$m**
text map `ex1'
b1 = 0 e1 = 02360 f1 = 020
b2 = 0 e2 = 02360 f2 = 020
data map `core1'
b1 = 0 e1 = 03500 f1 = 02000
b2 = 0175400 e2 = 0200000 f2 = 05500
***charp/s**
0124: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTLxNh@x&_
~
**charp/s**
_charp: T
_charp+02: this is a sentence.
_charp+026: Input file missing
**main.argc/d**
0177756: 2
***main.argv/3o**
0177762: 0177770 0177776 0177777
**0177770/s**
0177770: a.out
***main.argv/3o**
0177762: 0177770 0177776 0177777
***"/s**
0177770: a.out
**.=o**
0177770
**.-10/d**
0177756: 2
**$q**
=== Figure 3: Multiple function C program for stack trace ===
<code c>
int fcnt,gcnt,hcnt;
h(x,y)
{
int hi; register int hr;
hi = x+1;
hr = x-y+1;
hcnt++ ;
hj:
f(hr,hi);
}
g(p,q)
{
int gi; register int gr;
gi = q-p;
gr = q-p+1;
gcnt++ ;
gj:
h(gr,gi);
}
f(a,b)
{
int fi; register int fr;
fi = a+2*b;
fr = a+b;
fcnt++ ;
fj:
g(fr,fi);
}
main()
{
f(1,1);
}
</code>
=== Figure 4: ADB output for C program of Figure 3 ===
**adb**
**$c**
~h(04452,04451)
~g(04453,011124)
~f(02,04451)
~h(04450,04447)
~g(04451,011120)
~f(02,04447)
~h(04446,04445)
~g(04447,011114)
~f(02,04445)
~h(04444,04443)
**HIT DEL KEY**
adb
**,5$C**
~h(04452,04451)
x: 04452
y: 04451
hi: ?
~g(04453,011124)
p: 04453
q: 011124
gi: 04451
gr: ?
~f(02,04451)
a: 02
b: 04451
fi: 011124
fr: 04453
~h(04450,04447)
x: 04450
y: 04447
hi: 04451
hr: 02
~g(04451,011120)
p: 04451
q: 011120
gi: 04447
gr: 04450
**fcnt/d**
_fcnt: 1173
**gcnt/d**
_gcnt: 1173
**hcnt/d**
_hcnt: 1172
**h.x/d**
022004: 2346
**$q**
=== Figure 5: C program to decode tabs ===
<code c>
#define MAXLINE 80
#define YES 1
#define NO 0
#define TABSP 8
char input[] "data";
char ibuf[518];
int tabs[MAXLINE];
main()
{
int col, *ptab;
char c;
ptab = tabs;
settab(ptab); /*Set initial tab stops */
col = 1;
if(fopen(input,ibuf) < 0) {
printf("%s : not found\n",input);
exit(8);
}
while((c = getc(ibuf)) != -1) {
switch(c) {
case '\t': /* TAB */
while(tabpos(col) != YES) {
putchar(' '); /* put BLANK */
col++ ;
}
break;
case '\n': /*NEWLINE */
putchar('\n');
col = 1;
break;
default:
putchar(c);
col++ ;
}
}
}
/* Tabpos return YES if col is a tab stop */
tabpos(col)
int col;
{
if(col > MAXLINE)
return(YES);
else
return(tabs[col]);
}
/* Settab - Set initial tab stops */
settab(tabp)
int *tabp;
{
int i;
for(i = 0; i<= MAXLINE; i++)
(i%TABSP) ? (tabs[i] = NO) : (tabs[i] = YES);
}
</code>
=== Figure 6a: ADB output for C program of Figure 5 ===
**adb a.out -**
**settab+4:b**
**fopen+4:b**
**getc+4:b**
**tabpos+4:b**
**$b**
breakpoints
count bkpt command
1 ~tabpos+04
1 _getc+04
1 _fopen+04
1 ~settab+04
**settab,5?ia**
~settab: jsr r5,csv
~settab+04: tst -(sp)
~settab+06: clr 0177770(r5)
~settab+012: cmp $0120,0177770(r5)
~settab+020: blt ~settab+076
~settab+022:
**settab,5?i**
~settab: jsr r5,csv
tst -(sp)
clr 0177770(r5)
cmp $0120,0177770(r5)
blt ~settab+076
**:r**
a.out: running
breakpoint ~settab+04: tst -(sp)
**settab+4:d**
**:c**
a.out: running
breakpoint _fopen+04: mov 04(r5),nulstr+012
**$C**
_fopen(02302,02472)
~main(01,0177770)
col: 01
c: 0
ptab: 03500
**tabs,3/8o**
03500: 01 0 0 0 0 0 0 0
01 0 0 0 0 0 0 0
01 0 0 0 0 0 0 0
=== Figure 6b: ADB output for C program of Figure 5 ===
**:c**
a.out: running
breakpoint _getc+04: mov 04(r5),r1
**ibuf+6/20c**
__cleanu+0202: This is a test of
**:c**
a.out: running
breakpoint ~tabpos+04: cmp $0120,04(r5)
**tabpos+4:d**
**settab+4:b settab,5?ia**
**settab+4:b settab,5?ia; 0**
**getc+4,3:b main.c?C; 0**
**settab+4:b settab,5?ia; ptab/o; 0**
**$b**
breakpoints
count bkpt command
1 ~tabpos+04
3 _getc+04 main.c?C;0
1 _fopen+04
1 ~settab+04 settab,5?ia;ptab?o;0
~settab: jsr r5,csv
~settab+04: bpt
~settab+06: clr 0177770(r5)
~settab+012: cmp $0120,0177770(r5)
~settab+020: blt ~settab+076
~settab+022:
0177766: 0177770
0177744: @`
T0177744: T
h0177744: h
i0177744: i
s0177744: s
=== Figure 7: ADB output for C program with breakpoints ===
**adb ex3 -**
**h+4:b hcnt/d; h.hi/; h.hr/**
**g+4:b gcnt/d; g.gi/; g.gr/**
**f+4:b fcnt/d; f.fi/; f.fr/**
**:r**
ex3: running
_fcnt: 0
0177732: 214
symbol not found
**f+4:b fcnt/d; f.a/; f.b/; f.fi/**
**g+4:b gcnt/d; g.p/; g.q/; g.gi/**
**h+4:b hcnt/d; h.x/; h.y/; h.hi/**
**:c**
ex3: running
_fcnt: 0
0177746: 1
0177750: 1
0177732: 214
_gcnt: 0
0177726: 2
0177730: 3
0177712: 214
_hcnt: 0
0177706: 2
0177710: 1
0177672: 214
_fcnt: 1
0177666: 2
0177670: 3
0177652: 214
_gcnt: 1
0177646: 5
0177650: 8
0177632: 214
**HIT DEL**
**f+4:b fcnt/d; f.a/"a = "d; f.b/"b = "d; f.fi/"fi = "d**
**g+4:b gcnt/d; g.p/"p = "d; g.q/"q = "d; g.gi/"gi = "d**
**h+4:b hcnt/d; h.x/"x = "d; h.y/"h = "d; h.hi/"hi = "d**
**:r**
ex3: running
_fcnt: 0
0177746: a = 1
0177750: b = 1
0177732: fi = 214
_gcnt: 0
0177726: p = 2
0177730: q = 3
0177712: gi = 214
_hcnt: 0
0177706: x = 2
0177710: y = 1
0177672: hi = 214
_fcnt: 1
0177666: a = 2
0177670: b = 3
0177652: fi = 214
**HIT DEL**
**$q**
=== Figure 8: ADB address maps ===
<code>
a.out hdr text+data
|____|_____________________________|
0 D
core hdr text+data stack
|______|_____________________________......|________|
0 D S E
</code>
The following ''adb'' variables are set.
|| b || base of data || 0 ||
|| d || length of data || D ||
|| s || length of stack || S ||
|| t || length of text || 0 ||
=== Figure 9: ADB output for maps ===
**adb map core**
**$m**
text map `map'
b1 = 0 e1 = 0256 f1 = 020
b2 = 0 e2 = 0256 f2 = 020
data map `core'
b1 = 0 e1 = 0300 f1 = 02000
b2 = 0175400 e2 = 0200000 f2 = 02300
**$v**
variables
d = 0300
m = 0407
s = 02400
**$q**
=== Figure 10: Simple C program for illustrating formatting and patching ===
<code c>
char str1[] "This is a character string";
int one 1;
int number 456;
long lnum 1234;
float fpt 1.25;
char str2[] "This is the second character string";
main()
{
one = 2;
}
</code>
=== Figure 11: ADB output illustrating fancy formats ===
<code>
**adb map410 core410**
**<b,-1/8ona**
020000: 0 064124 071551 064440 020163 020141 064143 071141
_str1+016: 061541 062564 020162 072163 064562 063556 0 02
_number:
_number: 0710 0 02322 040240 0 064124 071551 064440
_str2+06: 020163 064164 020145 062563 067543 062156 061440 060550
_str2+026: 060562 072143 071145 071440 071164 067151 0147 0
savr5+02: 0 0 0 0 0 0 0 0
**<b,20/4o4^8Cn**
020000: 0 064124 071551 064440 @`@`This i
020163 020141 064143 071141 s a char
061541 062564 020162 072163 acter st
064562 063556 0 02 ring@`@`@b@`
_number: 0710 0 02322 040240 H@a@`@`R@d @@
0 064124 071551 064440 @`@`This i
020163 064164 020145 062563 s the se
067543 062156 061440 060550 cond cha
060562 072143 071145 071440 racter s
071164 067151 0147 0 tring@`@`@`
0 0 0 0 @`@`@`@`@`@`@`@`
0 0 0 0 @`@`@`@`@`@`@`@`
data address not found
**<b,20/4o4^8t8cna**
020000: 0 064124 071551 064440 This i
_str1+06: 020163 020141 064143 071141 s a char
_str1+016: 061541 062564 020162 072163 acter st
_str1+026: 064562 063556 0 02 ring
_number:
_number: 0710 0 02322 040240 HR
_fpt+02: 0 064124 071551 064440 This i
_str2+06: 020163 064164 020145 062563 s the se
_str2+016: 067543 062156 061440 060550 cond cha
_str2+026: 060562 072143 071145 071440 racter s
_str2+036: 071164 067151 0147 0 tring
savr5+02: 0 0 0 0
savr5+012: 0 0 0 0
data address not found
**<b,10/2b8t^2cn**
020000: 0 0
_str1: 0124 0150 Th
0151 0163 is
040 0151 i
0163 040 s
0141 040 a
0143 0150 ch
0141 0162 ar
0141 0143 ac
0164 0145 te
**$Q**
</code>
=== Figure 12: Directory and inode dumps ===
<code>
**adb dir -**
**=nt"Inode"t"Name"**
**0,-1?ut14cn**
Inode Name
0: 652 .
82 ..
5971 cap.c
5323 cap
0 pp
**adb /dev/src -**
**02000>b**
**?m<b**
new map `/dev/src'
b1 = 02000 e1 = 0100000000 f1 = 0
b2 = 0 e2 = 0 f2 = 0
**$v**
variables
b = 02000
**<b,-1?"flags"8ton"links,uid,gid"8t3bn"size"8tbrdn"addr"8t8un"times"8t2Y2na**
02000: flags 073145
links,uid,gid 0163 0164 0141
size 0162 10356
addr 28770 8236 25956 27766 25455 8236 25956 25206
times 1976 Feb 5 08:34:56 1975 Dec 28 10:55:15
02040: flags 024555
links,uid,gid 012 0163 0164
size 0162 25461
addr 8308 30050 8294 25130 15216 26890 29806 10784
times 1976 Aug 17 12:16:51 1976 Aug 17 12:16:51
02100: flags 05173
links,uid,gid 011 0162 0145
size 0147 29545
addr 25972 8306 28265 8308 25642 15216 2314 25970
times 1977 Apr 2 08:58:01 1977 Feb 5 10:21:44
</code>
+91
View File
@@ -0,0 +1,91 @@
=== ADB Summary ===
== Command Summary ==
a) formatted printing
|| ? format || print from ''a.out'' file according to format ||
|| / format || print from ''core'' file according to format ||
|| = format || print the value of dot ||
|| ?w expr || write expression into ''a.out'' file ||
|| /w expr || write expression into ''core'' file ||
|| ?l expr || locate expression in ''a.out'' file ||
b) breakpoint and program control
|| :b || set breakpoint at dot ||
|| :c || continue running program ||
|| :d || delete breakpoint ||
|| :k || kill the program being debugged ||
|| :r || run ''a.out'' file under ADB control ||
|| :s || single step ||
c) miscellaneous printing
|| $b || print current breakpoints ||
|| $c || C stack trace ||
|| $e || external variables ||
|| $f || floating registers ||
|| $m || print ADB segment maps ||
|| $q || exit from ADB ||
|| $r || general registers ||
|| $s || set offset for symbol match ||
|| $v || print ADB variables ||
|| $w || set output line width ||
d) calling the shell
|| ! || call shell to read rest of line ||
e) assignment to variables
|| >name || assign dot to variable or register name ||
== Format Summary ==
|| a || the value of dot ||
|| b || one byte in octal ||
|| c || one byte as a character ||
|| d || one word in decimal ||
|| f || two words in floating point ||
|| i || PDP 11 instruction ||
|| o || one word in octal ||
|| n || print a newline ||
|| r || print a blank space ||
|| s || a null terminated character string ||
|| nt || move to next n space tab ||
|| u || one word as unsigned integer ||
|| x || hexadecimal ||
|| Y || date ||
|| ^ || backup dot ||
|| "..." || print string ||
== Expression Summary ==
a) expression components
|| decimal integer || e.g. 256 ||
|| octal integer || e.g. 0277 ||
|| hexadecimal || e.g. #ff ||
|| symbols || e.g. flag _main main.argc ||
|| variables || e.g. <b ||
|| registers || e.g. <pc <r0 ||
|| (expression) || expression grouping ||
b) dyadic operators
|| + || add ||
|| - || subtract ||
|| * || multiply ||
|| % || integer division ||
|| & || bitwise and ||
|| | || bitwise or ||
|| # || round up to the next multiple ||
c) monadic operators
|| ~ || not ||
|| * || contents of location ||
|| - || integer negate ||
File diff suppressed because it is too large Load Diff
Binary file not shown.
+760
View File
@@ -0,0 +1,760 @@
====== A Tutorial Introduction to ADB ======
//J. F. Maranzano, S. R. Bourne//
//May 5, 1977//
===== 1. Introduction =====
ADB is a new debugging program that is available on
UNIX. It provides capabilities to look at "core" files
resulting from aborted programs, print output in a variety
of formats, patch files, and run programs with embedded
breakpoints. This document provides examples of the more
useful features of ADB. The reader is expected to be familiar
with the basic commands on UNIX with the C language, and
with References 1, 2 and 3.
===== 2. A Quick Survey =====
==== 2.1. Invocation ====
ADB is invoked as:
**adb objfile corefile**
where ''objfile'' is an executable UNIX file and ''corefile'' is a
core image file. Many times this will look like:
**adb a.out core**
or more simply:
**adb**
where the defaults are ''a.out'' and ''core'' respectively. The
filename minus (-) means ignore this argument as in:
**adb - core**
ADB has requests for examining locations in either file.
The **?** request examines the contents of ''objfile'',
the **/** request examines the ''corefile''. The general form of these
requests is:
**address ? format**
or
**address / format**
==== 2.2. Current Address ====
ADB maintains a current address, called dot, similar in
function to the current pointer in the UNIX editor. When an
address is entered, the current address is set to that location,
so that:
**0126?i**
sets dot to octal 126 and prints the instruction at that
address. The request:
**.,10/d**
prints 10 decimal numbers starting at dot. Dot ends up
referring to the address of the last item printed. When
used with the **?** or **/** requests, the current address can be
advanced by typing newline; it can be decremented by typing **^**.
Addresses are represented by expressions. Expressions
are made up from decimal, octal, and hexadecimal integers,
and symbols from the program under test. These may be combined
with the operators +, -, *, % (integer division), &
(bitwise and), | (bitwise inclusive or), # (round up to the
next multiple), and ~ (not). (All arithmetic within ADB is
32 bits.) When typing a symbolic address for a C program,
the user can type ''name'' or ''_name''; ADB will recognize both
forms.
==== 2.3. Formats ====
To print data, a user specifies a collection of letters
and characters that describe the format of the printout.
Formats are "remembered" in the sense that typing a request
without one will cause the new printout to appear in the
previous format. The following are the most commonly used
format letters.
|| b || one byte in octal ||
|| c || one byte as a character ||
|| o || one word in octal ||
|| d || one word in decimal ||
|| f || two words in floating point ||
|| i || PDP 11 instruction ||
|| s || a null terminated character string ||
|| a || the value of dot ||
|| u || one word as unsigned integer ||
|| n || print a newline ||
|| r || print a blank space ||
|| ^ || backup dot ||
(Format letters are also available for "long" values, for
example, `**D**' for long decimal, and `**F**' for double floating
point.) For other formats see the ADB manual.
==== 2.4. General Request Meanings ====
The general form of a request is:
**address,count command modifier**
which sets `dot' to ''address'' and executes the command ''count''
times.
The following table illustrates some general ADB command meanings:
^^ Command ^^ Meaning ^^
|| ? || Print contents from ''a.out'' file ||
|| / || Print contents from ''core'' file ||
|| = || Print value of "dot" ||
|| : || Breakpoint control ||
|| $ || Miscellaneous requests ||
|| ; || Request separator ||
|| ! || Escape to shell ||
ADB catches signals, so a user cannot use a quit signal
to exit from ADB. The request $q or $Q (or cntl-D) must be
used to exit from ADB.
===== 3. Debugging C Programs =====
==== 3.1. Debugging A Core Image ====
Consider the C program in Figure 1. The program is
used to illustrate a common error made by C programmers.
The object of the program is to change the lower case "t" to
upper case in the string pointed to by ''charp'' and then write
the character string to the file indicated by argument 1.
The bug shown is that the character "T" is stored in the
pointer ''charp'' instead of the string pointed to by ''charp''.
Executing the program produces a core file because of an out
of bounds memory reference.
ADB is invoked by:
**adb a.out core**
The first debugging request:
**$c**
is used to give a C backtrace through the subroutines
called. As shown in Figure 2 only one function (''main'') was
called and the arguments ''argc'' and ''argv'' have octal values 02
and 0177762 respectively. Both of these values look reasonable;
02 = two arguments, 0177762 = address on stack of
parameter vector.
The next request:
**$C**
is used to give a C backtrace plus an interpretation of all
the local variables in each function and their values in
octal. The value of the variable ''cc'' looks incorrect since
''cc'' was declared as a character.
The next request:
**$r**
prints out the registers including the program counter and
an interpretation of the instruction at that location.
The request:
**$e**
prints out the values of all external variables.
A map exists for each file handled by ADB. The map for
the ''a.out'' file is referenced by **?** whereas the map for ''core**
file is referenced by **/**. Furthermore, a good rule of thumb
is to use **?** for instructions and **/** for data when looking at
programs. To print out information about the maps type:
**$m**
This produces a report of the contents of the maps. More
about these maps later.
In our example, it is useful to see the contents of the
string pointed to by ''charp.'' This is done by:
***charp/s**
which says use ''charp'' as a pointer in the ''core'' file and print
the information as a character string. This printout
clearly shows that the character buffer was incorrectly
overwritten and helps identify the error. Printing the
locations around ''charp'' shows that the buffer is unchanged
but that the pointer is destroyed. Using ADB similarly, we
could print information about the arguments to a function.
The request:
**main.argc/d**
prints the decimal ''core'' image value of the argument ''argc'' in
the function //main.//
The request:
***main.argv,3/o**
prints the octal values of the three consecutive cells
pointed to by ''argv'' in the function ''main.'' Note that these
values are the addresses of the arguments to main. Therefore:
**0177770/s**
prints the ASCII value of the first argument. Another way
to print this value would have been
***"/s**
The " means ditto which remembers the last address typed, in
this case ''main.argc'' ; the ** * ** instructs ADB to use the address
field of the ''core'' file as a pointer.
The request:
**.=o**
prints the current address (not its contents) in octal which
has been set to the address of the first argument. The current
address, dot, is used by ADB to "remember" its current
location. It allows the user to reference locations relative
to the current address, for example:
**.-10/d**
==== 3.2. Multiple Functions ====
Consider the C program illustrated in Figure 3. This
program calls functions ''f,'' ''g,'' and ''h'' until the stack is
exhausted and a core image is produced.
Again you can enter the debugger via:
**adb**
which assumes the names ''a.out'' and ''core'' for the executable
file and core image file respectively. The request:
**$c**
will fill a page of backtrace references to //f,'' ''g,'' and ''h.//
Figure 4 shows an abbreviated list (typing ''DEL'' will terminate
the output and bring you back to ADB request level).
The request:
**,5$C**
prints the five most recent activations.
Notice that each function (''f,g,h'') has a counter of the
number of times it was called.
The request:
**fcnt/d**
prints the decimal value of the counter for the function //f.//
Similarly ''gcnt'' and ''hcnt'' could be printed. To print the
value of an automatic variable, for example the decimal
value of ''x'' in the last call of the function ''h,'' type:
**h.x/d**
It is currently not possible in the exported version to
print stack frames other than the most recent activation of
a function. Therefore, a user can print everything with **$C**
or the occurrence of a variable in the most recent call of a
function. It is possible with the **$C** request, however, to
print the stack frame starting at some address as **address$C.**
==== 3.3. Setting Breakpoints ====
Consider the C program in Figure 5. This program,
which changes tabs into blanks, is adapted from //Software//
''Tools'' by Kernighan and Plauger, pp. 18-27.
We will run this program under the control of ADB (see
Figure 6a) by:
**adb a.out -**
Breakpoints are set in the program as:
**address:b [request]**
The requests:
**settab+4:b**
**fopen+4:b**
**getc+4:b**
**tabpos+4:b**
set breakpoints at the start of these functions. C does not
generate statement labels. Therefore it is currently not
possible to plant breakpoints at locations other than function
entry points without a knowledge of the code generated
by the C compiler. The above addresses are entered as **symbol+4**
so that they will appear in any C backtrace since the
first instruction of each function is a call to the C save
routine (''csv''). Note that some of the functions are from the
C library.
To print the location of breakpoints one types:
**$b**
The display indicates a ''count'' field. A breakpoint is
bypassed //count'' ''-1'' times before causing a stop. The ''command//
field indicates the ADB requests to be executed each time
the breakpoint is encountered. In our example no //command//
fields are present.
By displaying the original instructions at the function
''settab'' we see that the breakpoint is set after the jsr to
the C save routine. We can display the instructions using
the ADB request:
**settab,5?ia**
This request displays five instructions starting at //settab//
with the addresses of each location displayed. Another
variation is:
**settab,5?i**
which displays the instructions with only the starting
address.
Notice that we accessed the addresses from the //a.out//
file with the **?** command. In general when asking for a
printout of multiple items, ADB will advance the current
address the number of bytes necessary to satisfy the
request; in the above example five instructions were displayed
and the current address was advanced 18 (decimal)
bytes.
To run the program one simply types:
**:r**
To delete a breakpoint, for instance the entry to the function
''settab,'' one types:
**settab+4:d**
To continue execution of the program from the breakpoint
type:
**:c**
Once the program has stopped (in this case at the
breakpoint for ''fopen),'' ADB requests can be used to display
the contents of memory. For example:
**$C**
to display a stack trace, or:
**tabs,3/8o**
to print three lines of 8 locations each from the array
called ''tabs.'' By this time (at location ''fopen)'' in the C program,
''settab'' has been called and should have set a one in
every eighth location of //tabs.//
==== 3.4. Advanced Breakpoint Usage ====
We continue execution of the program with:
**:c**
See Figure 6b. ''Getc'' is called three times and the contents
of the variable ''c'' in the function ''main'' are displayed each
time. The single character on the left hand edge is the
output from the C program. On the third occurrence of //getc//
the program stops. We can look at the full buffer of
characters by typing:
**ibuf+6/20c**
When we continue the program with:
**:c**
we hit our first breakpoint at ''tabpos'' since there is a tab
following the "This" word of the data.
Several breakpoints of ''tabpos'' will occur until the program
has changed the tab into equivalent blanks. Since we
feel that ''tabpos'' is working, we can remove the breakpoint at
that location by:
**tabpos+4:d**
If the program is continued with:
**:c**
it resumes normal execution after ADB prints the message
**a.out:running**
The UNIX quit and interrupt signals act on ADB itself
rather than on the program being debugged. If such a signal
occurs then the program being debugged is stopped and control
is returned to ADB. The signal is saved by ADB and is
passed on to the test program if:
**:c**
is typed. This can be useful when testing interrupt handling
routines. The signal is not passed on to the test
program if:
**:c 0**
is typed.
Now let us reset the breakpoint at ''settab'' and display
the instructions located there when we reach the breakpoint.
This is accomplished by:
**settab+4:b settab,5?ia** (*
It is also possible to execute the ADB requests for each
occurrence of the breakpoint but only stop after the third
occurrence by typing:
**getc+4,3:b main.c?C** (*
This request will print the local variable ''c'' in the function
''main'' at each occurrence of the breakpoint. The semicolon is
used to separate multiple ADB requests on a single line.
Warning: setting a breakpoint causes the value of dot
to be changed; executing the program under ADB does not
change dot. Therefore:
**settab+4:b .,5?ia**
-----------
(* Owing to a bug in early versions of ADB (including
the version distributed in Generic 3 UNIX)
these statements must be written as:
**settab+4:b settab,5?ia;0**
**getc+4,3:b main.c?C;0**
**settab+4:b settab,5?ia; ptab/o;0**
Note that **;0** will set dot to zero and stop at the
breakpoint.
**fopen+4:b**
will print the last thing dot was set to (in the example
''fopen+4'') ''not'' the current location (''settab+4'') at which the
program is executing.
A breakpoint can be overwritten without first deleting
the old breakpoint. For example:
**settab+4:b settab,5?ia; ptab/o** (*
could be entered after typing the above requests.
Now the display of breakpoints:
**$b**
shows the above request for the ''settab'' breakpoint. When the
breakpoint at ''settab'' is encountered the ADB requests are
executed. Note that the location at ''settab+4'' has been
changed to plant the breakpoint; all the other locations
match their original value.
Using the functions, ''f,'' ''g'' and ''h'' shown in Figure 3, we
can follow the execution of each function by planting non-stopping
breakpoints. We call ADB with the executable program
of Figure 3 as follows:
**adb ex3 -**
Suppose we enter the following breakpoints:
**h+4:b hcnt/d; h.hi/; h.hr/**
**g+4:b gcnt/d; g.gi/; g.gr/**
**f+4:b fcnt/d; f.fi/; f.fr/**
**:r**
Each request line indicates that the variables are printed
in decimal (by the specification **d**). Since the format is
not changed, the **d** can be left off all but the first
request.
The output in Figure 7 illustrates two points. First,
the ADB requests in the breakpoint line are not examined
until the program under test is run. That means any errors
in those ADB requests is not detected until run time. At
the location of the error ADB stops running the program.
The second point is the way ADB handles register variables.
ADB uses the symbol table to address variables.
Register variables, like ''f.fr'' above, have pointers to uninitialized
places on the stack. Therefore the message "symbol
not found".
Another way of getting at the data in this example is
to print the variables used in the call as:
**f+4:b fcnt/d; f.a/; f.b/; f.fi/**
**g+4:b gcnt/d; g.p/; g.q/; g.gi/**
**:c**
The operator / was used instead of ? to read values from
the ''core'' file. The output for each function, as shown in
Figure 7, has the same format. For the function ''f'', for
example, it shows the name and value of the //external//
variable ''fcnt.'' It also shows the address on the stack and
value of the variables //a,'' ''b'' and ''fi.//
Notice that the addresses on the stack will continue to
decrease until no address space is left for program execution
at which time (after many pages of output) the program
under test aborts. A display with names would be produced
by requests like the following:
**f+4:b fcnt/d; f.a/"a="d; f.b/"b="d; f.fi/"fi="d**
In this format the quoted string is printed literally and
the **d** produces a decimal display of the variables. The
results are shown in Figure 7.
==== 3.5. Other Breakpoint Facilities ====
(*) Arguments and change of standard input and output are
passed to a program as:
**:r arg1 arg2 ... <infile >outfile**
This request kills any existing program under test and
starts the ''a.out'' afresh.
(*) The program being debugged can be single stepped by:
**:s**
If necessary, this request will start up the program
being debugged and stop after executing the first
instruction.
(*) ADB allows a program to be entered at a specific address
by typing:
**address:r**
(*) The count field can be used to skip the first ''n'' breakpoints as:
**,n:r**
The request:
**,n:c**
may also be used for skipping the first ''n'' breakpoints
when continuing a program.
(*) A program can be continued at an address different from
the breakpoint by:
**address:c**
(*) The program being debugged runs as a separate process
and can be killed by:
**:k**
===== 4. Maps =====
UNIX supports several executable file formats. These
are used to tell the loader how to load the program file.
File type 407 is the most common and is generated by a C
compiler invocation such as **cc pgm.c**. A 410 file is produced
by a C compiler command of the form **cc -n pgm.c**,
whereas a 411 file is produced by **cc -i pgm.c**. ADB interprets
these different file formats and provides access to
the different segments through a set of maps (see Figure 8).
To print the maps type:
**$m**
In 407 files, both text (instructions) and data are
intermixed. This makes it impossible for ADB to differentiate
data from instructions and some of the printed symbolic
addresses look incorrect; for example, printing data
addresses as offsets from routines.
In 410 files (shared text), the instructions are separated
from data and **?* ** accesses the data part of the ''a.out**
file. The **?* ** request tells ADB to use the second part of
the map in the ''a.out'' file. Accessing data in the ''core'' file
shows the data after it was modified by the execution of the
program. Notice also that the data segment may have grown
during program execution.
In 411 files (separated I & D space), the instructions
and data are also separated. However, in this case, since
data is mapped through a separate set of segmentation registers,
the base of the data segment is also relative to
address zero. In this case since the addresses overlap it
is necessary to use the **?* ** operator to access the data space
of the ''a.out'' file. In both 410 and 411 files the corresponding
core file does not contain the program text.
Figure 9 shows the display of three maps for the same
program linked as a 407, 410, 411 respectively. The b, e,
and f fields are used by ADB to map addresses into file
addresses. The "f1" field is the length of the header at
the beginning of the file (020 bytes for an ''a.out'' file and
02000 bytes for a ''core'' file). The "f2" field is the displacement
from the beginning of the file to the data. For a
407 file with mixed text and data this is the same as the
length of the header; for 410 and 411 files this is the
length of the header plus the size of the text portion.
The "b" and "e" fields are the starting and ending
locations for a segment. Given an address, A, the location
in the file (either ''a.out'' or ''core'') is calculated as:
**b1<=A<=e1 => file address = (A-b1)+f1**
**b2<=A<=e2 => file address = (A-b2)+f2**
A user can access locations by using the ADB defined variables.
The **$v** request prints the variables initialized by
ADB:
|| b || base address of data segment ||
|| d || length of the data segment ||
|| s || length of the stack ||
|| t || length of the text ||
|| m || execution type (407,410,411) ||
In Figure 9 those variables not present are zero. Use
can be made of these variables by expressions such as:
**<b**
in the address field. Similarly the value of the variable
can be changed by an assignment request such as:
**02000>b**
that sets **b** to octal 2000. These variables are useful to
know if the file under examination is an executable or //core//
image file.
ADB reads the header of the ''core'' image file to find the
values for these variables. If the second file specified
does not seem to be a ''core'' file, or if it is missing then
the header of the executable file is used instead.
===== 5. Advanced Usage =====
It is possible with ADB to combine formatting requests
to provide elaborate displays. Below are several examples.
==== 5.1. Formatted dump ====
The line:
**<b,-1/4o4^8Cn**
prints 4 octal words followed by their ASCII interpretation
from the data space of the core image file. Broken down,
the various request pieces mean:
|| <b || The base address of the data segment. ||
|| <b,-1 || Print from the base address to the end of file. A negative count is used here and elsewhere to loop indefinitely or until some error condition (like end of file) is detected. ||
The format **4o4^8Cn** is broken down as follows:
|| 4o || Print 4 octal locations. ||
|| 4^ || Backup the current address 4 locations (to the original start of the field). ||
|| 8C || Print 8 consecutive characters using an escape convention; each character in the range 0 to 037 is printed as @ followed by the corresponding character in the range 0140 to 0177. An @ is printed as @@. ||
|| n || Print a newline. ||
The request:
**<b,<d/4o4^8Cn**
could have been used instead to allow the printing to stop
at the end of the data segment (<d provides the data segment
size in bytes).
The formatting requests can be combined with ADB's
ability to read in a script to produce a core image dump
script. ADB is invoked as:
**adb a.out core < dump**
to read in a script file, ''dump,'' of requests. An example of
such a script is:
**120$w**
**4095$s**
**$v**
**=3n**
**$m**
**=3n"C Stack Backtrace"**
**$C**
**=3n"C External Variables"**
**$e**
**=3n"Registers"**
**$r**
**0$s**
**=3n"Data Segment"**
**<b,-1/8ona**
The request **120$w** sets the width of the output to 120
characters (normally, the width is 80 characters). ADB
attempts to print addresses as:
**symbol + offset**
The request **4095$s** increases the maximum permissible offset
to the nearest symbolic address from 255 (default) to 4095.
The request **=** can be used to print literal strings. Thus,
headings are provided in this ''dump'' program with requests of
the form:
**=3n"C Stack Backtrace"**
that spaces three lines and prints the literal string. The
request **$v** prints all non-zero ADB variables (see Figure 8).
The request **0$s** sets the maximum offset for symbol matches
to zero thus suppressing the printing of symbolic labels in
favor of octal values. Note that this is only done for the
printing of the data segment. The request:
**<b,-1/8ona**
prints a dump from the base of the data segment to the end
of file with an octal address field and eight octal numbers
per line.
Figure 11 shows the results of some formatting requests
on the C program of Figure 10.
==== 5.2. Directory Dump ====
As another illustration (Figure 12) consider a set of
requests to dump the contents of a directory (which is made
up of an integer ''inumber'' followed by a 14 character name):
**adb dir -**
**=n8t"Inum"8t"Name"**
**0,-1? u8t14cn**
In this example, the **u** prints the ''inumber'' as an unsigned
decimal integer, the **8t** means that ADB will space to the
next multiple of 8 on the output line, and the **14c** prints
the 14 character file name.
==== 5.3. Ilist Dump ====
Similarly the contents of the ''ilist'' of a file system,
(e.g. /dev/src, on UNIX systems distributed by the UNIX Support
Group; see UNIX Programmer's Manual Section V) could be
dumped with the following set of requests:
**adb /dev/src -**
**02000>b**
**?m <b**
**<b,-1?"flags"8ton"links,uid,gid"8t3bn",size"8tbrdn"addr"8t8un"times"8t2Y2na**
In this example the value of the base for the map was
changed to 02000 (by saying **?m<b**) since that is the start of
an ''ilist'' within a file system. An artifice (**brd** above) was
used to print the 24 bit size field as a byte, a space, and
a decimal integer. The last access time and last modify
time are printed with the **2Y** operator. Figure 12 shows portions
of these requests as applied to a directory and file
system.
==== 5.4. Converting values ====
ADB may be used to convert values from one representation
to another. For example:
**072 = odx**
will print
**072 58 #3a**
which is the octal, decimal and hexadecimal representations
of 072 (octal). The format is remembered so that typing
subsequent numbers will print them in the given formats.
Character values may be converted similarly, for example:
**'a' = co**
prints
**a 0141**
It may also be used to evaluate expressions but be warned
that all binary operators have the same precedence which is
lower than that for unary operators.
===== 6. Patching =====
Patching files with ADB is accomplished with the //write,// **w** or **W**,
request (which is not like the ''ed'' editor write
command). This is often used in conjunction with the
''locate,'' **l** or **L** request. In general, the request syntax
for **l** and **w** are similar as follows:
**?l value**
The request **l** is used to match on two bytes, **L** is used for
four bytes. The request **w** is used to write two bytes,
whereas **W** writes four bytes. The **value** field in either
''locate'' or ''write'' requests is an expression. Therefore, decimal
and octal numbers, or character strings are supported.
In order to modify a file, ADB must be called as:
**adb -w file1 file2**
When called with this option, ''file1'' and ''file2'' are created if
necessary and opened for both reading and writing.
For example, consider the C program shown in Figure 10.
We can change the word "This" to "The " in the executable
file for this program, ''ex7'', by using the following requests:
**adb -w ex7 -**
**?l 'Th'**
**?W 'The '**
The request **?l** starts at dot and stops at the first match of
"Th" having set dot to the address of the location found.
Note the use of **?** to write to the ''a.out'' file. The form **?* **
would have been used for a 411 file.
More frequently the request will be typed as:
**?l 'Th'; ?s**
and locates the first occurrence of "Th" and print the
entire string. Execution of this ADB request will set dot
to the address of the "Th" characters.
As another example of the utility of the patching
facility, consider a C program that has an internal logic
flag. The flag could be set by the user through ADB and the
program run. For example:
**adb a.out -**
**:s arg1 arg2**
**flag/w 1**
**:c**
The **:s** request is normally used to single step through a
process or start a process in single step mode. In this
case it starts ''a.out'' as a subprocess with arguments **arg1** and **arg2**.
If there is a subprocess running ADB writes to it
rather than to the file so the **w** request causes ''flag'' to be
changed in the memory of the subprocess.
===== 7. Anomalies =====
Below is a list of some strange things that users
should be aware of.
- Function calls and arguments are put on the stack by the C save routine. Putting breakpoints at the entry point to routines means that the function appears not to have been called when the breakpoint occurs.
- When printing addresses, ADB uses either text or data symbols from the ''a.out'' file. This sometimes causes unexpected symbol names to be printed with data (e.g. ''savr5+022''). This does not happen if **?** is used for text (instructions) and **/** for data.
- ADB cannot handle C register variables in the most recently activated function.
===== 8. Acknowledgements =====
The authors are grateful for the thoughtful comments on
how to organize this document from R. B. Brandt, E. N. Pinson
and B. A. Tague. D. M. Ritchie made the system changes
necessary to accommodate tracing within ADB. He also participated
in discussions during the writing of ADB. His earlier
work with DB and CDB led to many of the features found in ADB.
===== 9. References =====
- D. M. Ritchie and K. Thompson, "The UNIX Time-Sharing System", CACM, July, 1974.
- B. W. Kernighan and D. M. Ritchie, "The C Programming Language", Prentice-Hall, 1978.
- K. Thompson and D. M. Ritchie, UNIX Programmer's Manual - 7th Edition, 1978.
- B. W. Kernighan and P. J. Plauger, "Software Tools", Addison-Wesley, 1976.
+318
View File
@@ -0,0 +1,318 @@
#include "defs.h"
#ifdef CROSS
# include </usr/include/ctype.h>
#else
# include <ctype.h>
#endif
static int savlastf;
static long savframe;
static int savpc;
static char isymbol[MAXSYMLEN + 2];
/*
* service routines for expression reading
*/
static int
symchar(dig)
{
if (lastc == '\\') {
readchar();
return TRUE;
}
return (isalpha(lastc) || lastc == '_' || (dig && isdigit(lastc)));
}
static void
readsym()
{
register char *p;
p = isymbol;
do {
if (p < &isymbol[MAXSYMLEN])
*p++ = lastc;
readchar();
} while (symchar(1));
*p++ = 0;
}
static void
chkloc(frame)
long frame;
{
readsym();
do {
if (localsym(frame) == 0)
error(BADLOC);
expv = localval;
} while (! eqsym(cache_sym(symbol), isymbol, '~'));
}
static struct SYMbol *
lookupsym(symstr)
char *symstr;
{
register struct SYMbol *symp, *sc;
symset();
while ((symp = symget())) {
sc = cache_by_string(symstr);
if (sc)
return sc;
if (eqsym(no_cache_sym(symp), symstr, '_'))
break;
}
/*
* We did not enter anything into the cache (no sense inserting hundreds
* of symbols which didn't match) while examining the (entire) symbol table.
* Now that we have a match put it into the cache (doing a lookup on it is
* the easiest way).
*/
if (symp)
(void)cache_sym(symp);
return symp;
}
static int
convdig(c)
int c;
{
if (isdigit(c))
return c - '0';
if (isxdigit(c))
return c - 'a' + 10;
return 17;
}
/*
* name [ . local ] | number | . | ^ | <var | <register | 'x |
*/
int
item(a)
{
int base, d, frpt, regptr;
char savc, hex;
long frame;
union {
float r;
long i;
} real;
register struct SYMbol *symp;
hex = FALSE;
readchar();
if (symchar(0)) {
readsym();
if (lastc == '.') {
frame = (kernel ? corhdr[KR5] : uframe[FRAME_R5]) & ALIGNED;
lastframe = 0;
callpc = kernel ? (-2) : uframe[FRAME_PC];
while (errflg == 0) {
savpc = callpc;
findroutine(frame);
if (eqsym(cache_sym(symbol), isymbol, '~'))
break;
lastframe = frame;
frame = get(frame, DSP) & ALIGNED;
if (frame == 0) {
error(NOCFN);
}
}
savlastf = lastframe;
savframe = frame;
readchar();
if (symchar(0)) {
expv = frame;
chkloc(expv);
}
} else if ((symp = lookupsym(isymbol)) == 0) {
error(BADSYM);
} else {
expv = symp->value;
}
lp--;
} else if (isdigit(lastc) ||
(hex = TRUE, lastc == '#' && isxdigit(readchar())))
{
expv = 0;
base = (lastc == '0' || octal) ? 8 : (hex ? 16 : 10);
while ((hex ? isxdigit(lastc) : isdigit(lastc))) {
expv *= base;
d = convdig(lastc);
if (d >= base) {
error(BADSYN);
}
expv += d;
readchar();
if (expv == 0 && (lastc == 'x' || lastc == 'X')) {
hex = TRUE;
base = 16;
readchar();
}
}
if (lastc == '.' && (base == 10 || expv == 0) && ! hex) {
real.r = expv;
frpt = 0;
base = 10;
while (isdigit(readchar())) {
real.r *= base;
frpt++;
real.r += lastc - '0';
}
while (frpt--) {
real.r /= base;
}
expv = real.i;
}
lp--;
} else if (lastc == '.') {
readchar();
if (symchar(0)) {
lastframe = savlastf;
callpc = savpc;
findroutine(savframe);
chkloc(savframe);
} else {
expv = dot;
}
lp--;
} else if (lastc == '"') {
expv = ditto;
} else if (lastc == '+') {
expv = inkdot(dotinc);
} else if (lastc == '^') {
expv = inkdot(-dotinc);
} else if (lastc == '<') {
savc = rdc();
regptr = getreg(savc);
if (regptr != NOREG) {
expv = uframe[regptr];
} else if ((base = varchk(savc)) != -1) {
expv = var[base];
} else {
error(BADVAR);
}
} else if (lastc == '\'') {
d = 4;
expv = 0;
while (quotchar()) {
if (d--) {
if (d == 1)
expv <<= 16;
expv |= (d & 1) ? lastc : (lastc << 8);
} else {
error(BADSYN);
}
}
} else if (a) {
error(NOADR);
} else {
lp--;
return 0;
}
return 1;
}
/*
* item | monadic item | (expr) |
*/
int
term(a)
{
switch (readchar()) {
case '*':
term(a | 1);
expv = chkget(expv, DSP);
return 1;
case '@':
term(a | 1);
expv = chkget(expv, ISP);
return 1;
case '-':
term(a | 1);
expv = -expv;
return 1;
case '~':
term(a | 1);
expv = ~expv;
return 1;
case '(':
expr(2);
if (*lp != ')') {
error(BADSYN);
} else {
lp++; return 1;
}
default:
lp--;
return item(a);
}
}
/*
* term | term dyadic expr |
*/
int
expr(a)
{
int rc;
long lhs;
rdc();
lp--;
rc = term(a);
while (rc) {
lhs = expv;
switch (readchar()) {
case '+': term(a|1); expv += lhs; break;
case '-': term(a|1); expv = lhs - expv; break;
case '#': term(a|1); expv = roundn(lhs, expv); break;
case '*': term(a|1); expv *= lhs; break;
case '%': term(a|1); expv = lhs/expv; break;
case '&': term(a|1); expv &= lhs; break;
case '|': term(a|1); expv |= lhs; break;
case ')': if (! (a & 2)) error(BADKET);
default: lp--; return rc;
}
}
return rc;
}
int
varchk(name)
{
if (isdigit(name))
return name - '0';
if (isalpha(name))
return (name & 037) - 1 + 10;
return -1;
}
int
eqsym(s1, s2, c)
register char *s1, *s2;
int c;
{
if (! strcmp(s1, s2))
return TRUE;
if (*s1++ == c)
return ! strcmp(s1, s2);
return FALSE;
}
+44
View File
@@ -0,0 +1,44 @@
#include "defs.h"
int
findroutine(cframe)
long cframe;
{
register int narg, inst;
int lastpc, back2;
char v;
v = FALSE;
localok = FALSE;
lastpc = callpc;
callpc = get(cframe+2, DSP);
back2 = get(leng(callpc - 2), ISP);
inst = get(leng(callpc-4), ISP);
if (inst == 04737) { /* jsr pc, *$... */
narg = 1;
} else if ((inst & ~077) == 04700) { /* jsr pc, ... */
narg = 0;
v = (inst != 04767);
} else if ((back2 & ~077) == 04700) {
narg = 0;
v = TRUE;
} else {
errflg = NOCFN;
return 0;
}
if (findsym((v ? lastpc : ((inst==04767 ? callpc : 0) + back2)), ISYM) == -1 && !v)
symbol = NULL;
else
localok = TRUE;
inst = get(leng(callpc), ISP);
if (inst == 062706) { /* add $n, sp */
narg += get(leng(callpc + 2), ISP) / 2;
return narg;
}
if (inst == 05726 || inst == 010026) /* tst (sp)+ or mov r0, (sp)+ */
return narg + 1;
if (inst == 022626) { /* cmp (sp)+, (sp)+ */
return narg + 2;
}
return narg;
}
+315
View File
@@ -0,0 +1,315 @@
#include "defs.h"
#include <sys/wait.h>
#ifdef CROSS
# include </usr/include/ctype.h>
#else
# include <ctype.h>
#endif
void
scanform(icount, ifp, itype, ptype)
long icount;
char *ifp;
{
char *fp;
char modifier;
int fcount, init=1;
long savdot;
while (icount) {
fp = ifp;
if (init == 0 && findsym(shorten(dot), ptype) == 0 && maxoff) {
print("\n%s:%16t", cache_sym(symbol));
}
savdot = dot;
init = 0;
/* now loop over format */
while (*fp && errflg == 0) {
modifier = *fp;
if (isdigit(modifier)) {
fcount = 0;
modifier = *fp++;
while (isdigit(modifier)) {
fcount *= 10;
fcount += modifier-'0';
}
fp--;
} else {
fcount = 1;
}
if (*fp == 0)
break;
fp = exform(fcount, fp, itype, ptype);
}
dotinc = dot - savdot;
dot = savdot;
if (errflg) {
if (icount < 0) {
errflg = 0;
break;
} else {
error(errflg);
}
}
if (--icount) {
dot = inkdot(dotinc);
}
if (mkfault) {
error((char *)0);
}
}
}
static void
printesc(c)
{
c &= STRIP;
if (c < SP || c > '~' || c == '@') {
print("@%c", (c == '@') ? '@' : c ^ 0140);
} else {
printc(c);
}
}
char *
exform(fcount, ifp, itype, ptype)
int fcount;
char *ifp;
int itype, ptype;
{
/* execute single format item `fcount' times
* sets `dotinc' and moves `dot'
* returns address of next format item
*/
u_int w;
long savdot, wx;
char *fp = 0;
int c, modifier;
struct {
long sa;
int sb, sc;
} fw;
while (fcount > 0) {
fp = ifp;
c = *fp;
//int longpr = (c >= 'A' && c <= 'Z') || (c == 'f');
if (itype == NSP || *fp == 'a') {
wx = dot;
w = dot;
} else {
w = get(dot, itype);
//if (longpr)
// wx = itol(w, get(inkdot(2), itype));
//else
wx = w;
}
if (c == 'F') {
fw.sb = get(inkdot(4), itype);
fw.sc = get(inkdot(6), itype);
}
if (errflg)
return(fp);
if (mkfault)
error((char *)0);
var[0] = wx;
modifier = *fp++;
dotinc = 4;
if (! (printptr - printbuf) && modifier != 'a')
print("%16m");
switch(modifier) {
case SP: case TB:
break;
case 't': case 'T':
print("%T", fcount);
return fp;
case 'r': case 'R':
print("%M", fcount);
return fp;
case 'a':
psymoff(dot, ptype, ":%16t");
dotinc = 0;
break;
case 'p':
psymoff(var[0], ptype, "%16t");
break;
case 'u':
print("%-8u", w);
break;
case 'U':
print("%-16U", wx);
break;
case 'c': case 'C':
if (modifier == 'C') {
printesc(w & LOBYTE);
} else {
printc(w & LOBYTE);
}
dotinc = 1;
break;
case 'b': case 'B':
print("%-4x", w & LOBYTE);
dotinc = 1;
break;
case 's': case 'S':
savdot = dot;
dotinc = 1;
while ((c = get(dot, itype) & LOBYTE) && errflg == 0) {
dot = inkdot(1);
if (modifier == 'S') {
printesc(c);
} else {
printc(c);
}
endline();
}
dotinc = dot - savdot + 1;
dot = savdot;
break;
case 'x':
print("%-8x", w);
break;
case 'X':
print("%-16X", wx);
break;
case 'Y':
print("%-24Y", wx);
break;
case 'q':
print("%-8q", w);
break;
case 'Q':
print("%-16Q", wx);
break;
case 'o':
case 'w':
print("%-8o", w);
break;
case 'O':
case 'W':
print("%-16O", wx);
break;
case 'i':
printins(itype, dot, w); printc(EOR);
break;
case 'd':
print("%-8d", w);
break;
case 'D':
print("%-16D", wx);
break;
case 'f':
*(double *)&fw = 0.0;
fw.sa = wx;
print("%-16.9f", *(double *)&fw);
dotinc = 4;
break;
case 'F':
fw.sa = wx;
print("%-32.18F", *(double *)&fw);
dotinc = 8;
break;
case 'n': case 'N':
printc('\n');
dotinc = 0;
break;
case '"':
dotinc = 0;
while (*fp != '"' && *fp) {
printc(*fp++);
}
if (*fp) {
fp++;
}
break;
case '^':
dot = inkdot(-dotinc * fcount);
return fp;
case '+':
dot = inkdot(fcount);
return fp;
case '-':
dot = inkdot(-fcount);
return fp;
default:
error(BADMOD);
}
if (itype != NSP) {
dot = inkdot(dotinc);
}
fcount--;
endline();
}
return fp;
}
void
unox()
{
int rc, status, unixpid;
char *argp = lp;
while (lastc != EOR) {
rdc();
}
if ((unixpid = fork()) == 0) {
signal(SIGINT, sigint);
signal(SIGQUIT, sigqit);
*lp = 0;
execl("/bin/sh", "sh", "-c", argp, (char*)0);
exit(16);
} else if (unixpid == -1) {
error(NOFORK);
} else {
signal(SIGINT, SIG_IGN);
while ((rc = wait(&status)) != unixpid && rc != -1);
signal(SIGINT, sigint);
printc('!');
lp--;
}
}
long
inkdot(incr)
{
long newdot;
newdot = dot + incr;
if ((dot ^ newdot) >> 24) {
error(ADWRAP);
}
return newdot;
}
+86
View File
@@ -0,0 +1,86 @@
/*
* Input routines
*/
#include "defs.h"
int lastc = EOR;
static char line[LINSIZ];
int
eol(c)
{
return (c == EOR || c == ';');
}
int
rdc()
{
do {
readchar();
} while (lastc == SP || lastc == TB );
return lastc;
}
int
readchar()
{
if (eof) {
lastc = '\0';
} else {
if (lp == 0) {
lp = line;
do {
eof = (read(infile, lp, 1) == 0);
if (mkfault)
error((char *)0);
} while (eof == 0 && *lp++ != EOR);
*lp = 0;
lp = line;
}
lastc = *lp;
if (lastc)
lp++;
}
return lastc;
}
int
nextchar()
{
if (eol(rdc())) {
lp--;
return 0;
}
return lastc;
}
int
quotchar()
{
if (readchar() == '\\')
return readchar();
if (lastc == '\'')
return 0;
return lastc;
}
void
getformat(deformat)
char *deformat;
{
register char *fptr;
register int quote;
fptr = deformat;
quote = FALSE;
while ((quote ? readchar()!=EOR : !eol(readchar()))) {
if ((*fptr++ = lastc) == '"') {
quote = ~quote;
}
}
lp--;
if (fptr != deformat) {
*fptr++ = '\0';
}
}
+167
View File
@@ -0,0 +1,167 @@
#include "defs.h"
#include <fcntl.h>
char *Ipath = "/share/adb";
static int exitflg;
long
roundn(a, b)
long a, b;
{
long w;
w = ((a + b - 1) / b) * b;
return w;
}
/*
* error handling
*/
void
chkerr()
{
if (errflg || mkfault)
error(errflg);
}
void
error(msg)
const char *msg;
{
errflg = msg;
iclose(0, 1);
oclose();
longjmp(erradb, 1);
}
void
fault(a)
{
signal(a, fault);
lseek(infile, 0L, 2);
mkfault++;
}
/*
* set up files and initial address mappings
*/
int
main(argc, argv)
register char **argv;
int argc;
{
short mynamelen; /* length of program name */
maxfile = 1L << 24;
if (isatty(0))
myname = *argv;
else
myname = "adb";
mynamelen = strlen(myname);
#ifdef TIOCGETP
ioctl(0, TIOCGETP, &adbtty);
ioctl(0, TIOCGETP, &usrtty);
#else
tcgetattr(0, &adbtty);
tcgetattr(0, &usrtty);
#endif
while (argc > 1) {
if (strcmp("-w", argv[1]) == 0) {
wtflag = O_RDWR;
argc--;
argv++;
continue;
}
if (strcmp("-k", argv[1]) == 0) {
kernel++;
argc--;
argv++;
continue;
}
if (strcmp("-I", argv[1]) == 0) {
Ipath = argv[2];
argc -= 2;
argv += 2;
continue;
}
break;
}
if (argc > 1) {
symfil = argv[1];
}
if (argc > 2) {
corfil = argv[2];
}
argcount = argc;
setsym();
setcor();
/* set up variables for user */
maxoff = MAXOFF;
maxpos = MAXPOS;
var[VARB] = datbas;
var[VARD] = datsiz;
var[VARE] = entrypt;
var[VARM] = magic;
var[VARS] = stksiz;
var[VART] = txtsiz;
sigint = signal(SIGINT, SIG_IGN);
if (sigint != SIG_IGN) {
sigint = fault;
signal(SIGINT, fault);
}
sigqit = signal(SIGQUIT, SIG_IGN);
siginterrupt(SIGINT, 1);
siginterrupt(SIGQUIT, 1);
setjmp(erradb);
if (executing) {
delbp();
}
executing = FALSE;
for (;;) {
flushbuf();
if (errflg) {
print("%s\n", errflg);
exitflg = (errflg != 0);
errflg = 0;
}
if (mkfault) {
mkfault = 0;
printc(EOR);
print("%s\n", myname);
}
if (myname && ! infile) {
write(1, myname, mynamelen);
write(1, "> ", 2);
}
lp = 0;
rdc();
lp--;
if (eof) {
if (infile) {
iclose(-1, 0);
eof = 0;
longjmp(erradb, 1);
}
done();
} else {
exitflg = 0;
}
command(0, lastcom);
if (lp && lastc != EOR) {
error(NOEOR);
}
}
}
void
done()
{
endpcs();
exit(exitflg);
}
+30
View File
@@ -0,0 +1,30 @@
#include "defs.h"
const char BADMOD[] = "bad modifier";
const char BADCOM[] = "bad command";
const char BADSYM[] = "symbol not found";
const char BADLOC[] = "automatic variable not found";
const char NOCFN[] = "c routine not found";
const char NOMATCH[] = "cannot locate value";
const char NOBKPT[] = "no breakpoint set";
const char BADKET[] = "unexpected ')'";
const char NOADR[] = "address expected";
const char NOPCS[] = "no process";
const char BADVAR[] = "bad variable";
const char BADTXT[] = "text address not found";
const char BADDAT[] = "data address not found";
const char ODDADR[] = "odd address";
const char EXBKPT[] = "too many breakpoints";
const char A68BAD[] = "bad a68 frame";
const char A68LNK[] = "bad a68 link";
const char ADWRAP[] = "address wrap around";
const char BADEQ[] = "unexpected `='";
const char BADWAIT[] = "wait error: process disappeared!";
const char ENDPCS[] = "process terminated";
const char NOFORK[] = "try again";
const char BADSYN[] = "syntax error";
const char NOEOR[] = "newline expected";
const char SZBKPT[] = "bkpt: command too long";
const char LONGFIL[] = "filename too long";
const char NOTOPEN[] = "cannot open";
const char TOODEEP[] = "$<< nesting too deep";
+439
View File
@@ -0,0 +1,439 @@
/*
* Instruction printing
*/
#include "defs.h"
/*
* Flags of instruction formats.
*/
#define FRD1 (1 << 0) /* rd, ... */
#define FRD2 (1 << 1) /* .., rd, ... */
#define FRT1 (1 << 2) /* rt, ... */
#define FRT2 (1 << 3) /* .., rt, ... */
#define FRT3 (1 << 4) /* .., .., rt */
#define FRS1 (1 << 5) /* rs, ... */
#define FRS2 (1 << 6) /* .., rs, ... */
#define FRS3 (1 << 7) /* .., .., rs */
#define FRSB (1 << 8) /* ... (rs) */
#define FCODE (1 << 9) /* immediate shifted <<6 */
#define FOFF16 (1 << 11) /* 16-bit relocatable offset */
#define FHIGH16 (1 << 12) /* high 16-bit relocatable offset */
#define FOFF18 (1 << 13) /* 18-bit PC-relative relocatable offset shifted >>2 */
#define FAOFF18 (1 << 14) /* 18-bit PC-relative relocatable offset shifted >>2 */
#define FAOFF28 (1 << 15) /* 28-bit absolute relocatable offset shifted >>2 */
#define FSA (1 << 16) /* 5-bit shift amount */
#define FSEL (1 << 17) /* optional 3-bit COP0 register select */
#define FSIZE (1 << 18) /* bit field size */
#define FMSB (1 << 19) /* bit field msb */
#define FRTD (1 << 20) /* set rt to rd number */
#define FCODE16 (1 << 21) /* immediate shifted <<16 */
#define FSYS (1 << 22) /* syscall */
struct optable {
unsigned opcode;
unsigned mask;
const char *name;
unsigned type;
};
static const struct optable optable [] = {
{ 0x34000000, 0xffe00000, "li", FRT1 | FOFF16 }, // ori
{ 0x24000000, 0xffe00000, "li", FRT1 | FOFF16 }, // addiu
{ 0x00000021, 0xfc1f07ff, "move", FRD1 | FRS2 }, // addu
{ 0x00000040, 0xffffffff, "ssnop", 0 }, // nop
{ 0x00000020, 0xfc0007ff, "add", FRD1 | FRS2 | FRT3 },
{ 0x20000000, 0xfc000000, "addi", FRT1 | FRS2 | FOFF16 },
{ 0x24000000, 0xfc000000, "addiu", FRT1 | FRS2 | FOFF16 },
{ 0x00000021, 0xfc0007ff, "addu", FRD1 | FRS2 | FRT3 },
{ 0x00000024, 0xfc0007ff, "and", FRD1 | FRS2 | FRT3 },
{ 0x30000000, 0xfc000000, "andi", FRT1 | FRS2 | FOFF16 },
{ 0x10000000, 0xffff0000, "b", FAOFF18 },
{ 0x04110000, 0xffff0000, "bal", FAOFF18 },
{ 0x10000000, 0xfc000000, "beq", FRS1 | FRT2 | FOFF18 },
{ 0x50000000, 0xfc000000, "beql", FRS1 | FRT2 | FOFF18 },
{ 0x04010000, 0xfc1f0000, "bgez", FRS1 | FOFF18 },
{ 0x04110000, 0xfc1f0000, "bgezal", FRS1 | FOFF18 },
{ 0x04130000, 0xfc1f0000, "bgezall", FRS1 | FOFF18 },
{ 0x04030000, 0xfc1f0000, "bgezl", FRS1 | FOFF18 },
{ 0x1c000000, 0xfc1f0000, "bgtz", FRS1 | FOFF18 },
{ 0x5c000000, 0xfc1f0000, "bgtzl", FRS1 | FOFF18 },
{ 0x18000000, 0xfc1f0000, "blez", FRS1 | FOFF18 },
{ 0x58000000, 0xfc1f0000, "blezl", FRS1 | FOFF18 },
{ 0x04000000, 0xfc1f0000, "bltz", FRS1 | FOFF18 },
{ 0x04100000, 0xfc1f0000, "bltzal", FRS1 | FOFF18 },
{ 0x04120000, 0xfc1f0000, "bltzall", FRS1 | FOFF18 },
{ 0x04020000, 0xfc1f0000, "bltzl", FRS1 | FOFF18 },
{ 0x14000000, 0xfc000000, "bne", FRS1 | FRT2 | FOFF18 },
{ 0x54000000, 0xfc000000, "bnel", FRS1 | FRT2 | FOFF18 },
{ 0x0000000d, 0xfc00ffff, "break", FCODE16 },
{ 0x70000021, 0xfc0007ff, "clo", FRD1 | FRS2 | FRTD },
{ 0x70000020, 0xfc0007ff, "clz", FRD1 | FRS2 | FRTD },
{ 0x4200001f, 0xffffffff, "deret", 0 },
{ 0x41606000, 0xffe0ffff, "di", FRT1 },
{ 0x0000001a, 0xfc00ffff, "div", FRS1 | FRT2 },
{ 0x0000001b, 0xfc00ffff, "divu", FRS1 | FRT2 },
{ 0x000000c0, 0xffffffff, "ehb", 0 },
{ 0x41606020, 0xffe0ffff, "ei", FRT1 },
{ 0x42000018, 0xffffffff, "eret", 0 },
{ 0x7c000000, 0xfc00003f, "ext", FRT1 | FRS2 | FSA | FSIZE },
{ 0x7c000004, 0xfc00003f, "ins", FRT1 | FRS2 | FSA | FMSB },
{ 0x08000000, 0xfc000000, "j", FAOFF28 },
{ 0x0c000000, 0xfc000000, "jal", FAOFF28 },
{ 0x00000009, 0xfc1f07ff, "jalr", FRD1 | FRS2 },
{ 0x00000409, 0xfc1f07ff, "jalr.hb", FRD1 | FRS2 },
{ 0x00000008, 0xfc1fffff, "jr", FRS1 },
{ 0x00000408, 0xfc1fffff, "jr.hb", FRS1 },
{ 0x80000000, 0xfc000000, "lb", FRT1 | FOFF16 | FRSB },
{ 0x90000000, 0xfc000000, "lbu", FRT1 | FOFF16 | FRSB },
{ 0x84000000, 0xfc000000, "lh", FRT1 | FOFF16 | FRSB },
{ 0x94000000, 0xfc000000, "lhu", FRT1 | FOFF16 | FRSB },
{ 0xc0000000, 0xfc000000, "ll", FRT1 | FOFF16 | FRSB },
{ 0x3c000000, 0xffe00000, "lui", FRT1 | FHIGH16 },
{ 0x8c000000, 0xfc000000, "lw", FRT1 | FOFF16 | FRSB },
{ 0x88000000, 0xfc000000, "lwl", FRT1 | FOFF16 | FRSB },
{ 0x98000000, 0xfc000000, "lwr", FRT1 | FOFF16 | FRSB },
{ 0x70000000, 0xfc00ffff, "madd", FRS1 | FRT2 },
{ 0x70000001, 0xfc00ffff, "maddu", FRS1 | FRT2 },
{ 0x40000000, 0xffe007f8, "mfc0", FRT1 | FRD2 | FSEL },
{ 0x00000010, 0xffff07ff, "mfhi", FRD1 },
{ 0x00000012, 0xffff07ff, "mflo", FRD1 },
{ 0x0000000b, 0xfc0007ff, "movn", FRD1 | FRS2 | FRT3 },
{ 0x0000000a, 0xfc0007ff, "movz", FRD1 | FRS2 | FRT3 },
{ 0x70000004, 0xfc00ffff, "msub", FRS1 | FRT2 },
{ 0x70000005, 0xfc00ffff, "msubu", FRS1 | FRT2 },
{ 0x40800000, 0xffe007f8, "mtc0", FRT1 | FRD2 | FSEL },
{ 0x00000011, 0xfc1fffff, "mthi", FRS1 },
{ 0x00000013, 0xfc1fffff, "mtlo", FRS1 },
{ 0x70000002, 0xfc0007ff, "mul", FRD1 | FRS2 | FRT3 },
{ 0x00000018, 0xfc00ffff, "mult", FRS1 | FRT2 },
{ 0x00000019, 0xfc00ffff, "multu", FRS1 | FRT2 },
{ 0x00000000, 0xffffffff, "nop", 0 },
{ 0x00000027, 0xfc0007ff, "nor", FRD1 | FRS2 | FRT3 },
{ 0x00000025, 0xfc0007ff, "or", FRD1 | FRS2 | FRT3 },
{ 0x34000000, 0xfc000000, "ori", FRT1 | FRS2 | FOFF16 },
{ 0x7c00003b, 0xffe007ff, "rdhwr", FRT1 | FRD2 },
{ 0x41400000, 0xffe007ff, "rdpgpr", FRD1 | FRT2 },
{ 0x00200002, 0xffe0003f, "ror", FRD1 | FRT2 | FSA },
{ 0x00000046, 0xfc0007ff, "rorv", FRD1 | FRT2 | FRS3 },
{ 0xa0000000, 0xfc000000, "sb", FRT1 | FOFF16 | FRSB },
{ 0xe0000000, 0xfc000000, "sc", FRT1 | FOFF16 | FRSB },
{ 0x7000003f, 0xfc00003f, "sdbbp", FCODE },
{ 0x7c000420, 0xffe007ff, "seb", FRD1 | FRT2 },
{ 0x7c000620, 0xffe007ff, "seh", FRD1 | FRT2 },
{ 0xa4000000, 0xfc000000, "sh", FRT1 | FOFF16 | FRSB },
{ 0x00000000, 0xffe0003f, "sll", FRD1 | FRT2 | FSA },
{ 0x00000004, 0xfc0007ff, "sllv", FRD1 | FRT2 | FRS3 },
{ 0x0000002a, 0xfc0007ff, "slt", FRD1 | FRS2 | FRT3 },
{ 0x28000000, 0xfc000000, "slti", FRT1 | FRS2 | FOFF16 },
{ 0x2c000000, 0xfc000000, "sltiu", FRT1 | FRS2 | FOFF16 },
{ 0x0000002b, 0xfc0007ff, "sltu", FRD1 | FRS2 | FRT3 },
{ 0x00000003, 0xffe0003f, "sra", FRD1 | FRT2 | FSA },
{ 0x00000007, 0xfc0007ff, "srav", FRD1 | FRT2 | FRS3 },
{ 0x00000002, 0xffe0003f, "srl", FRD1 | FRT2 | FSA },
{ 0x00000006, 0xfc0007ff, "srlv", FRD1 | FRT2 | FRS3 },
{ 0x00000022, 0xfc0007ff, "sub", FRD1 | FRS2 | FRT3 },
{ 0x00000023, 0xfc0007ff, "subu", FRD1 | FRS2 | FRT3 },
{ 0xac000000, 0xfc000000, "sw", FRT1 | FOFF16 | FRSB },
{ 0xa8000000, 0xfc000000, "swl", FRT1 | FOFF16 | FRSB },
{ 0xb8000000, 0xfc000000, "swr", FRT1 | FOFF16 | FRSB },
{ 0x0000000f, 0xfffff83f, "sync", FCODE },
{ 0x0000000c, 0xfc00003f, "syscall", FSYS },
{ 0x00000034, 0xfc00ffff, "teq", FRS1 | FRT2 },
{ 0x040c0000, 0xfc1f0000, "teqi", FRS1 | FOFF16 },
{ 0x00000030, 0xfc00ffff, "tge", FRS1 | FRT2 },
{ 0x04080000, 0xfc1f0000, "tgei", FRS1 | FOFF16 },
{ 0x04090000, 0xfc1f0000, "tgeiu", FRS1 | FOFF16 },
{ 0x00000031, 0xfc00ffff, "tgeu", FRS1 | FRT2 },
{ 0x00000032, 0xfc00ffff, "tlt", FRS1 | FRT2 },
{ 0x040a0000, 0xfc1f0000, "tlti", FRS1 | FOFF16 },
{ 0x040b0000, 0xfc1f0000, "tltiu", FRS1 | FOFF16 },
{ 0x00000033, 0xfc00ffff, "tltu", FRS1 | FRT2 },
{ 0x00000036, 0xfc00ffff, "tne", FRS1 | FRT2 },
{ 0x040e0000, 0xfc1f0000, "tnei", FRS1 | FOFF16 },
{ 0x42000020, 0xfe00003f, "wait", FCODE },
{ 0x41c00000, 0xffe007ff, "wrpgpr", FRD1 | FRT2 },
{ 0x7c0000a0, 0xffe007ff, "wsbh", FRD1 | FRT2 },
{ 0x00000026, 0xfc0007ff, "xor", FRD1 | FRS2 | FRT3 },
{ 0x38000000, 0xfc000000, "xori", FRT1 | FRS2 | FOFF16 },
{ 0, 0, 0, 0 },
};
static const char *systab[] = {
"indir", /* 0 - indir*/
"exit",
"fork",
"read",
"write",
"open",
"close",
"wait4",
NULL, /* 8 - unused */
"link",
"unlink", /* 10 */
"execv",
"chdir",
"fchdir",
"mknod",
"chmod",
"chown",
"chflags",
"fchflags",
"lseek",
"getpid", /* 20 */
"mount",
"umount",
"__sysctl",
"getuid",
"geteuid", /* 25 */
"ptrace",
"getppid",
NULL, /* 28 - unused */
NULL, /* 29 - unused */
NULL, /* 30 - unused */
"sigaction", /* 31 - sigaction */
"sigprocmask", /* 32 - sigprocmask */
"access",
"sigpending", /* 34 - sigpending */
"sigaltstack", /* 35 - sigaltstack */
"sync",
"kill",
"stat",
"_getlogin", /* 39 - _getlogin */
"lstat",
"dup",
"pipe",
"setlogin", /* 43 - unused */
"profil",
"setuid", /* 45 - setuid */
"seteuid", /* 46 - seteuid */
"getgid",
"getegid",
"setgid", /* 49 - setgid */
"setegid", /* 50 - setegid */
"acct",
"phys",
"lock",
"ioctl",
"reboot",
NULL, /* 56 - unused */
"symlink",
"readlink",
"execve",
"umask",
"chroot",
"fstat",
NULL, /* 63 - unused */
NULL, /* 64 - unused */
"pselect", /* 65 - pselect */
"vfork",
NULL, /* 67 - unused */
NULL, /* 68 - unused */
"sbrk",
NULL, /* 70 - unused */
NULL, /* 71 - unused */
NULL, /* 72 - unused */
NULL, /* 73 - unused */
NULL, /* 74 - unused */
NULL, /* 75 - unused */
"vhangup",
NULL, /* 77 - unused */
NULL, /* 78 - unused */
"getgroups",
"setgroups",
"getpgrp",
"setpgrp",
"setitimer",
NULL, /* 84 - unused */
NULL, /* 85 - unused */
"getitimer",
NULL, /* 87 - unused */
NULL, /* 88 - unused */
"getdtablesize",
"dup2",
NULL, /* 91 - unused */
"fcntl",
"select",
NULL, /* 94 - unused */
"fsync",
"setpriority",
"socket",
"connect",
"accept",
"getpriority",
"send",
"recv", /* 102 - recv */
"sigreturn",
"bind",
"setsockopt",
"listen",
"sigsuspend", /* 107 - sigsuspend */
NULL, /* 108 - unused */
NULL, /* 109 - unused */
NULL, /* 110 - unused */
NULL, /* 111 - unused */
"old sigstack", /* 112 - sigstack COMPAT-43 for zork */
"recvmsg",
"sendmsg",
NULL, /* 115 - unused */
"gettimeofday",
"getrusage",
"getsockopt",
NULL, /* 119 - unused */
"readv",
"writev",
"settimeofday",
"fchown",
"fchmod",
"recvfrom",
NULL, /* 126 - unused */
NULL, /* 127 - unused */
"rename",
"truncate",
"ftruncate",
"flock",
NULL, /* 132 - unused */
"sendto",
"shutdown",
"socketpair",
"mkdir",
"rmdir",
"utimes",
NULL, /* 139 - unused */
"adjtime",
"getpeername",
NULL, /* 142 - unused */
NULL, /* 143 - unused */
"getrlimit",
"setrlimit",
"killpg",
NULL, /* 147 - unused */
"setquota",
"quota",
"getsockname",
/*
* 2.11BSD special calls
*/
NULL, /* 151 - unused */
"nostk",
"fetchi",
"ucall",
"fperr",
};
#define NUMSYSCALLS (sizeof (systab) / sizeof (char *))
static const char *const regname[32] = {
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
};
/*
* Print the mips instruction at address MEMADDR in debugged memory.
* Returns length of the instruction, in bytes, which is
* always INSNLEN.
*/
void
printins (space, memaddr, word)
unsigned memaddr, word;
{
const struct optable *op;
for (op=optable; op->mask; op++) {
if ((word & op->mask) == op->opcode)
break;
}
if (! op->mask) {
print (".word%8t%x", word);
return;
}
print ("%s%8t", op->name);
/*
* First register.
*/
if (op->type & FRD1) /* rd, ... */
print ("%s", regname[word >> 11 & 31]);
if (op->type & FRT1) /* rt, ... */
print ("%s", regname[word >> 16 & 31]);
if (op->type & FRS1) /* rs, ... */
print ("%s", regname[word >> 21 & 31]);
/*
* Second register.
*/
if (op->type & FRD2) /* .., rd, ... */
print (", %s", regname[word >> 11 & 31]);
if (op->type & FRT2) /* .., rt, ... */
print (", %s", regname[word >> 16 & 31]);
if (op->type & FRS2) /* .., rs, ... */
print (", %s", regname[word >> 21 & 31]);
/*
* Third register.
*/
if (op->type & FRT3) /* .., .., rt */
print (", %s", regname[word >> 16 & 31]);
if (op->type & FRS3) /* .., .., rs */
print (", %s", regname[word >> 21 & 31]);
/*
* Immediate argument.
*/
if (op->type & FSEL) {
/* optional COP0 register select */
if (word & 7)
print (", %x", word & 7);
} else if (op->type & FSYS) {
/* Syscall */
unsigned code = (word & ~op->mask) >> 6;
if (code < NUMSYSCALLS && systab[code])
print("%s", systab[code]);
else
print("%d", code);
} else if (op->type & FCODE) {
/* Non-relocatable offset */
print ("%x", (word & ~op->mask) >> 6);
} else if (op->type & FCODE16) {
print ("%x", (word & ~op->mask) >> 16);
} else if (op->type & FSA) {
print (", %x", word >> 6 & 0x1f);
} else if (op->type & FOFF16) {
/* Relocatable offset */
print (", %x", word & 0xffff);
} else if (op->type & FOFF18) {
unsigned addr = ((signed short) (word & 0xffff) << 2) + memaddr + 4;
print (", ");
psymoff(addr, ISYM, "");
} else if (op->type & FHIGH16) {
print (", %x", word & 0xffff);
} else if (op->type & FAOFF18) {
unsigned addr = ((signed short) (word & 0xffff) << 2) + memaddr + 4;
psymoff(addr, ISYM, "");
} else if (op->type & FAOFF28) {
unsigned addr = (word & 0x3ffffff) << 2;
psymoff(addr, ISYM, "");
}
/*
* Last argument.
*/
if (op->type & FRSB) /* ... (rs) */
print ("(%s)", regname[word >> 21 & 31]);
if (op->type & FSIZE) /* bit field size */
print (", %x", ((word >> 11) & 0x1f) + 1);
if (op->type & FMSB) /* bit field msb */
print (", %x", ((word >> 11) & 0x1f) + 1 -
((word >> 6) & 0x1f));
}
+393
View File
@@ -0,0 +1,393 @@
#include "defs.h"
#include <stdarg.h>
int outfile = 1;
char *printptr = printbuf;
static char *digitptr;
void
printc(c)
int c;
{
char d;
char *q;
int posn, tabs, p;
if (mkfault)
return;
*printptr = c;
if (c == EOR) {
tabs = 0;
posn = 0;
q = printbuf;
for (p=0; p<printptr-printbuf; p++) {
d = printbuf[p];
if ((p & 7)==0 && posn) {
tabs++;
posn = 0;
}
if (d == SP) {
posn++;
} else {
while (tabs > 0) {
*q++ = TB;
tabs--;
}
while (posn > 0) {
*q++ = SP;
posn--;
}
*q++ = d;
}
}
*q++ = EOR;
write(outfile, printbuf, q - printbuf);
printptr = printbuf;
} else if (c == TB) {
*printptr++ = SP;
while ((printptr - printbuf) & 7) {
*printptr++ = SP;
}
} else if (c) {
printptr++;
}
if (printptr >= &printbuf[MAXLIN-9]) {
write(outfile, printbuf, printptr - printbuf);
printptr = printbuf;
}
}
void
flushbuf()
{
if (printptr != printbuf) {
printc(EOR);
}
}
static int
convert(cp)
register char **cp;
{
register char c;
int n = 0;
while ((c = *(*cp)++) >= '0' && c <= '9') {
n = n*10 + c - '0';
}
(*cp)--;
return n;
}
static void
printnum(n, fmat, base)
register int n;
{
register char k;
register int *dptr;
int digs[15];
dptr = digs;
if (n < 0 && fmat == 'd') {
n = -n;
*digitptr++ = '-';
}
while (n) {
*dptr++ = ((u_int) n) % base;
n = ((u_int) n ) / base;
}
if (dptr == digs) {
*dptr++ = 0;
}
while (dptr != digs) {
k = *--dptr;
*digitptr++ = k + ((k <= 9) ? '0' : 'a'-10);
}
}
static void
printoct(o, s)
long o;
int s;
{
int i;
long po = o;
char digs[12];
if (s) {
if (po < 0) {
po = -po;
*digitptr++ = '-';
} else if (s > 0)
*digitptr++='+';
}
for (i=0; i<=11; i++) {
digs[i] = po & 7;
po >>= 3;
}
digs[10] &= 03;
digs[11] = 0;
for (i=11; i>=0; i--) {
if (digs[i])
break;
}
for (i++; i>=0; i--) {
*digitptr++ = digs[i] + '0';
}
}
static void
printlong(lx, fmat, base)
long lx;
int fmat, base;
{
int digs[20], *dptr;
char k;
unsigned long f, g;
dptr = digs;
f = lx;
if (fmat == 'x')
*digitptr++ = '#';
else if (fmat == 'D' && lx < 0) {
*digitptr++ = '-';
f = -lx;
}
while (f) {
g = f / base;
*dptr++ = f - g * base;
f = g;
}
if (dptr == digs) {
*dptr++ = 0;
}
while (dptr != digs) {
k = *--dptr;
*digitptr++ = k + ((k <= 9) ? '0' : 'a'-10);
}
}
static void
printdate(tvec)
long tvec;
{
register int i;
register char *timeptr;
timeptr = ctime(&tvec);
for (i=20; i<24; i++)
*digitptr++ = timeptr[i];
for (i=3; i<19; i++)
*digitptr++ = timeptr[i];
}
void
print(char *fmat, ...)
{
va_list args, prev_args;
char *fptr, *s;
int width, prec;
char c, adj;
int decpt, n;
char digits[64];
union {
int int32;
float float32;
} word;
va_start(args, fmat);
fptr = fmat;
while ((c = *fptr++)) {
if (c != '%') {
printc(c);
continue;
}
if (*fptr == '-') {
adj = 'l';
fptr++;
} else {
adj = 'r';
}
width = convert(&fptr);
if (*fptr == '*') {
width = va_arg(args, int);
fptr++;
}
if (*fptr == '.') {
fptr++;
prec = convert(&fptr);
if (*fptr == '*') {
prec = va_arg(args, int);
fptr++;
}
} else
prec = -1;
digitptr = digits;
prev_args = args;
word.int32 = va_arg(args, int);
s = 0;
switch (c = *fptr++) {
case 'd':
case 'u':
printnum(word.int32, c, 10);
break;
case 'o':
printoct(word.int32, 0);
break;
case 'q':
case 'x':
printlong(word.int32, 'x', 16);
break;
case 'Y':
printdate(word.int32);
break;
case 'D':
case 'U':
printlong(word.int32, c, 10);
break;
case 'O':
printoct(word.int32, 0);
break;
case 'Q':
case 'X':
printlong(word.int32, 'x', 16);
break;
case 'c':
printc(word.int32);
break;
case 's':
s = (char*) word.int32;
break;
case 'f':
case 'F':
s = ecvt(word.float32, prec, &decpt, &n);
*digitptr++ = n ? '-' : '+';
*digitptr++ = (decpt <= 0) ? '0' : *s++;
if (decpt > 0) {
decpt--;
}
*digitptr++ = '.';
while (*s && prec-- ) {
*digitptr++ = *s++;
}
while (*--digitptr=='0');
digitptr += (digitptr - digits >= 3) ? 1 : 2;
if (decpt) {
*digitptr++ = 'e';
printnum(decpt, 'd', 10);
}
s = 0;
prec = -1;
break;
case 'm':
args = prev_args;
break;
case 'M':
width = word.int32;
break;
case 'T':
case 't':
if (c == 'T') {
width = word.int32;
} else {
args = prev_args;
}
if (width) {
width -= (printptr - printbuf) % width;
}
break;
default:
printc(c);
args = prev_args;
}
if (s == 0) {
*digitptr = 0;
s = digits;
}
n = strlen(s);
n = (prec < n && prec >= 0) ? prec : n;
width -= n;
if (adj == 'r') {
while (width-- > 0)
printc(SP);
}
while (n--)
printc(*s++);
while (width-- > 0)
printc(SP);
digitptr = digits;
}
va_end(args);
}
#define MAXIFD 5
struct {
int fd;
long r9;
} istack[MAXIFD];
int ifiledepth;
void
iclose(stack, err)
{
if (err) {
if (infile) {
close(infile);
infile = 0;
}
while (--ifiledepth >= 0) {
if (istack[ifiledepth].fd) {
close(istack[ifiledepth].fd);
infile = 0;
}
}
ifiledepth = 0;
} else if (stack == 0) {
if (infile) {
close(infile);
infile = 0;
}
} else if (stack > 0) {
if (ifiledepth >= MAXIFD) {
error(TOODEEP);
}
istack[ifiledepth].fd = infile;
istack[ifiledepth].r9 = var[9];
ifiledepth++;
infile = 0;
} else {
if (infile) {
close(infile);
infile = 0;
}
if (ifiledepth > 0) {
infile = istack[--ifiledepth].fd;
var[9] = istack[ifiledepth].r9;
}
}
}
void
oclose()
{
if (outfile != 1) {
flushbuf();
close(outfile);
outfile = 1;
}
}
void
endline()
{
if ((printptr - printbuf) >= maxpos)
printc('\n');
}
+108
View File
@@ -0,0 +1,108 @@
/*
* Sub process control
*/
#include "defs.h"
void
subpcs(modif)
{
register int check;
int execsig, runmode;
register BKPTR bkptr;
char *comptr;
execsig = 0;
loopcnt = cntval;
switch (modif) {
case 'd': case 'D': /* delete breakpoint */
bkptr = scanbkpt(shorten(dot));
if (! bkptr)
error(NOBKPT);
bkptr->flag = 0;
if (pid)
del1bp(bkptr);
return;
case 'b': case 'B': /* set breakpoint */
bkptr = scanbkpt(shorten(dot));
if (bkptr) {
bkptr->flag = 0;
if (pid)
del1bp(bkptr);
}
for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) {
if (bkptr->flag == 0)
break;
}
if (bkptr == 0) {
bkptr = (BKPTR) malloc(sizeof *bkptr);
if (! bkptr) {
error(SZBKPT);
} else {
bkptr->nxtbkpt = bkpthead;
bkpthead=bkptr;
}
}
bkptr->loc = dot;
bkptr->initcnt = bkptr->count = cntval;
bkptr->flag = BKPTSET;
check = MAXCOM-1;
comptr = bkptr->comm;
rdc();
lp--;
do {
*comptr++ = readchar();
} while (check-- && lastc != EOR);
*comptr = 0;
lp--;
if (! check)
error(EXBKPT);
if (pid)
set1bp(bkptr);
return;
case 'k': case 'K': /* exit */
if (! pid)
error(NOPCS);
print("%d: killed", pid);
endpcs();
return;
case 'r': case 'R': /* run program */
endpcs();
setup();
setbp();
runmode = PT_CONTINUE;
break;
case 's': case 'S': /* single step */
runmode = PT_STEP;
if (pid) {
execsig = getsig(signo);
} else {
setup();
loopcnt--;
}
break;
case 'c': case 'C': case 0: /* continue with optional signal */
if (pid == 0)
error(NOPCS);
runmode = PT_CONTINUE;
execsig = getsig(signo);
break;
default:
error(BADMOD);
return;
}
if (loopcnt > 0 && runpcs(runmode, execsig)) {
print("breakpoint%16t");
} else {
print("stopped at%16t");
}
printpc();
}
+426
View File
@@ -0,0 +1,426 @@
#include "defs.h"
#include <fcntl.h>
const REGLIST reglist [FRAME_WORDS] = {
{ "at", FRAME_R1 }, /* 0 */
{ "v0", FRAME_R2 }, /* 1 */
{ "v1", FRAME_R3 }, /* 2 */
{ "a0", FRAME_R4 }, /* 3 */
{ "a1", FRAME_R5 }, /* 4 */
{ "a2", FRAME_R6 }, /* 5 */
{ "a3", FRAME_R7 }, /* 6 */
{ "t0", FRAME_R8 }, /* 7 */
{ "t1", FRAME_R9 }, /* 8 */
{ "t2", FRAME_R10 }, /* 9 */
{ "t3", FRAME_R11 }, /* 10 */
{ "t4", FRAME_R12 }, /* 11 */
{ "t5", FRAME_R13 }, /* 12 */
{ "t6", FRAME_R14 }, /* 13 */
{ "t7", FRAME_R15 }, /* 14 */
{ "s0", FRAME_R16 }, /* 15 */
{ "s1", FRAME_R17 }, /* 16 */
{ "s2", FRAME_R18 }, /* 17 */
{ "s3", FRAME_R19 }, /* 18 */
{ "s4", FRAME_R20 }, /* 19 */
{ "s5", FRAME_R21 }, /* 20 */
{ "s6", FRAME_R22 }, /* 21 */
{ "s7", FRAME_R23 }, /* 22 */
{ "t8", FRAME_R24 }, /* 23 */
{ "t9", FRAME_R25 }, /* 24 */
{ "gp", FRAME_GP }, /* 25 */
{ "sp", FRAME_SP }, /* 26 */
{ "fp", FRAME_FP }, /* 27 */
{ "ra", FRAME_RA }, /* 28 */
{ "lo", FRAME_LO }, /* 29 */
{ "hi", FRAME_HI }, /* 30 */
{ "status", FRAME_STATUS}, /* 31 */
{ "pc", FRAME_PC }, /* 32 */
};
static const REGLIST kregs[] = { // TODO
{ "r1", FRAME_R1 }, /* 0 */
{ "r2", FRAME_R2 }, /* 1 */
{ "r3", FRAME_R3 }, /* 2 */
{ "r4", FRAME_R4 }, /* 3 */
{ "r5", FRAME_R5 }, /* 4 */
{ "r6", FRAME_R6 }, /* 5 */
{ "sp", FRAME_SP }, /* 26 */
};
static void
printmap(s, amap)
char *s;
MAP *amap;
{
int file;
file = amap->ufd;
print("%s%12t`%s'\n", s, file < 0 ? "-" :
file == fcor ? corfil : symfil);
print("b1 = %-12Q", amap->b1);
print("e1 = %-12Q", amap->e1);
print("f1 = %-12Q", amap->f1);
print("\n");
print("b2 = %-12Q", amap->b2);
print("e2 = %-12Q", amap->e2);
print("f2 = %-12Q", amap->f2);
printc(EOR);
}
static void
printregs()
{
register const REGLIST *p;
int v;
if (kernel) {
// TODO
for (p=kregs; p<&kregs[7]; p++) {
v = corhdr[p->roffs];
print("%s%8t%x%8t", p->rname, v);
valpr(v, DSYM);
printc(EOR);
}
} else {
print (" t0 = %9x s0 = %9x t8 = %9x lo = %9x\n",
uframe [FRAME_R8], uframe [FRAME_R16],
uframe [FRAME_R24], uframe [FRAME_LO]);
print ("at = %9x t1 = %9x s1 = %9x t9 = %9x hi = %9x\n",
uframe [FRAME_R1], uframe [FRAME_R9], uframe [FRAME_R17],
uframe [FRAME_R25], uframe [FRAME_HI]);
print ("v0 = %9x t2 = %9x s2 = %9x status = %9x\n",
uframe [FRAME_R2], uframe [FRAME_R10],
uframe [FRAME_R18], uframe [FRAME_STATUS]);
print ("v1 = %9x t3 = %9x s3 = %9x pc = %9x\n",
uframe [FRAME_R3], uframe [FRAME_R11],
uframe [FRAME_R19], uframe [FRAME_PC]);
print ("a0 = %9x t4 = %9x s4 = %9x gp = %9x\n",
uframe [FRAME_R4], uframe [FRAME_R12],
uframe [FRAME_R20], uframe [FRAME_GP]);
print ("a1 = %9x t5 = %9x s5 = %9x sp = %9x\n",
uframe [FRAME_R5], uframe [FRAME_R13],
uframe [FRAME_R21], uframe [FRAME_SP]);
print ("a2 = %9x t6 = %9x s6 = %9x fp = %9x\n",
uframe [FRAME_R6], uframe [FRAME_R14],
uframe [FRAME_R22], uframe [FRAME_FP]);
print ("a3 = %9x t7 = %9x s7 = %9x ra = %9x\n",
uframe [FRAME_R7], uframe [FRAME_R15],
uframe [FRAME_R23], uframe [FRAME_RA]);
printpc();
}
}
/*
* general printing routines ($)
*/
void
printtrace(modif)
{
int narg, i, stat, name, limit;
u_int dynam;
register BKPTR bkptr;
char hi, lo;
int word, stack = 0;
char *comptr;
long argp, frame, link;
register struct SYMbol *symp;
if (cntflg == 0) {
cntval = -1;
}
switch (modif) {
case '<':
if (cntval == 0) {
while (readchar() != EOR)
;
lp--;
break;
}
if (rdc() == '<') {
stack = 1;
} else {
stack = 0;
lp--;
}
/* fall thru ... */
case '>': {
char file[64];
char Ifile[128];
int index;
index = 0;
if (rdc() != EOR) {
do {
file[index++] = lastc;
if (index >= 63)
error(LONGFIL);
} while (readchar() != EOR);
file[index] = 0;
if (modif == '<') {
if (Ipath) {
strcpy(Ifile, Ipath);
strcat(Ifile, "/");
strcat(Ifile, file);
}
if (strcmp(file, "-") != 0) {
iclose(stack, 0);
infile = open(file, 0);
if (infile < 0) {
infile = open(Ifile, 0);
}
} else {
lseek(infile, 0L, 0);
}
if (infile < 0) {
infile = 0;
error(NOTOPEN);
} else {
if (cntflg) {
var[9] = cntval;
} else {
var[9] = 1;
}
}
} else {
oclose();
outfile = open(file, O_CREAT | O_WRONLY, 0644);
lseek(outfile, 0L, 2);
}
} else {
if (modif == '<') {
iclose(-1, 0);
} else {
oclose();
}
}
lp--;
}
break;
case 'o':
octal = TRUE;
break;
case 'd':
octal = FALSE;
break;
case 'q': case 'Q': case '%':
done();
case 'w': case 'W':
maxpos = adrflg ? adrval : MAXPOS;
break;
case 's': case 'S':
maxoff = adrflg ? adrval : MAXOFF;
break;
case 'v':
print("variables\n");
for (i=0; i<=35; i++) {
if (var[i]) {
printc(i + (i <= 9 ? '0' : 'a'-10));
print(" = %Q\n", var[i]);
}
}
break;
case 'm': case 'M':
printmap("? map", &txtmap);
printmap("/ map", &datmap);
break;
case 0: case '?':
if (pid) {
print("pcs id = %d\n", pid);
} else {
print("no process\n");
}
sigprint();
flushbuf();
case 'r': case 'R':
printregs();
return;
case 'f': case 'F':
// No FPU registers
return;
case 'c': case 'C':
// TODO
frame = (adrflg ? adrval :
(kernel ? corhdr[FRAME_R5] : uframe[FRAME_R5])) & ALIGNED;
lastframe = 0;
callpc = (adrflg ? get(frame + 2, DSP) :
(kernel ? (-2) : uframe[FRAME_PC]));
while (cntval--) {
chkerr();
print("%Q: ", frame); /* Add frame address info */
narg = findroutine(frame);
print("%s(", cache_sym(symbol));
argp = frame+4;
if (--narg >= 0) {
print("%o", get(argp, DSP));
}
while (--narg >= 0) {
argp += 2;
print(",%o", get(argp, DSP));
}
/* Add return-PC info. Force printout of
* symbol+offset (never just a number! ) by using
* max possible offset. Overlay has already been set
* properly by findfn.
*/
print(") from ");
{
int savmaxoff = maxoff;
maxoff = ((unsigned)-1)>>1;
psymoff((long)callpc, ISYM, "");
maxoff = savmaxoff;
}
printc('\n');
if (modif == 'C') {
while (localsym(frame)) {
word = get(localval, DSP);
print("%8t%s:%10t", cache_sym(symbol));
if (errflg) {
print("?\n");
errflg = 0;
} else {
print("%o\n", word);
}
}
}
lastframe = frame;
frame = get(frame, DSP) & ALIGNED;
if (kernel ? ((u_int)frame > ((u_int)0140000 + USIZE)) :
(frame == 0))
break;
}
break;
case 'e': case 'E': /* print externals */
symset();
while ((symp = symget())) {
chkerr();
if (symp->type == (N_EXT | N_DATA) ||
symp->type == (N_EXT | N_BSS)) {
print("%s:%12t%o\n", no_cache_sym(symp),
get(leng(symp->value), DSP));
}
}
break;
case 'a': case 'A':
frame = adrflg ? adrval : uframe[FRAME_R4];
while (cntval--) {
chkerr();
stat = get(frame, DSP);
dynam = get(frame+2, DSP);
link = get(frame+4, DSP);
if (modif == 'A') {
print("%8O:%8t%-8o,%-8o,%-8o", frame, stat, dynam, link);
}
if (stat == 1)
break;
if (errflg)
error(A68BAD);
if (get(link-4, ISP) != 04767) {
if (get(link-2, ISP) != 04775)
error(A68LNK);
print(" ? ");
} else {
print("%8t");
name = shorten(link) + get(link-2, ISP);
valpr(name, ISYM);
name = get(leng(name -2), ISP);
print("%8t\"");
limit = 8;
do {
word = get(leng(name), DSP);
name += 2;
lo = word & LOBYTE;
hi = (word >> 8) & LOBYTE;
printc(lo);
printc(hi);
} while (lo && hi && limit--);
printc('"');
}
limit = 4;
i = 6;
print("%24targs:%8t");
while (limit--) {
print("%8t%o", get(frame + i, DSP));
i += 2;
}
printc(EOR);
frame = dynam;
}
errflg = 0;
flushbuf();
break;
/* set default c frame */
case 'b': case 'B': /* print breakpoints */
print("breakpoints\ncount%8tbkpt%24tcommand\n");
for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) {
if (bkptr->flag) {
print("%-8.8d", bkptr->count);
psymoff(leng(bkptr->loc), ISYM, "%24t");
comptr = bkptr->comm;
while (*comptr)
printc(*comptr++);
}
}
break;
default:
error(BADMOD);
}
}
int
getreg(regnam)
{
register const REGLIST *p;
register char *regptr;
char regnxt;
if (kernel) /* not supported */
return NOREG;
regnxt = readchar();
for (p=reglist; p<&reglist[NREG]; p++) {
regptr = p->rname;
if ((regnam == *regptr++) && (regnxt == *regptr))
return p->roffs;
}
lp--;
return NOREG;
}
void
printpc()
{
dot = uframe[FRAME_PC];
psymoff(dot, ISYM, ":%16t");
printins(ISP, dot, chkget(dot, ISP));
printc(EOR);
}
void
sigprint()
{
#ifndef CROSS
if (signo >= 0 && signo < NSIG)
print("%s", sys_siglist[signo]);
else
#endif
print("unknown signal %d", signo);
}
+296
View File
@@ -0,0 +1,296 @@
/*
* Service routines for sub process control
*/
#include "defs.h"
#include <fcntl.h>
#include <sys/wait.h>
static int userpc = 1;
int
getsig(sig)
{
return expr(0) ? shorten(expv) : sig;
}
static void
bpwait()
{
register int w;
int stat;
signal(SIGINT, SIG_IGN);
while ((w = wait(&stat)) != pid && w != -1)
;
signal(SIGINT, sigint);
#ifdef TIOCGETP
ioctl(0, TIOCGETP, &usrtty);
ioctl(0, TIOCSETP, &adbtty);
#else
tcgetattr(0, &usrtty);
tcsetattr(0, TCSANOW, &adbtty);
#endif
if (w == -1) {
pid = 0;
errflg = BADWAIT;
} else if ((stat & 0177) != 0177) {
signo = stat & 0177;
if (signo) {
sigprint();
}
if (stat & 0200) {
print(" - core dumped");
close(fcor);
setcor();
}
pid = 0;
errflg = ENDPCS;
} else {
signo = stat>>8;
if (signo != SIGTRAP) {
sigprint();
} else {
signo = 0;
}
flushbuf();
}
}
/*
* get REG values from pcs
*/
static void
readregs()
{
register u_int i;
for (i=0; i<NREG; i++) {
uframe[reglist[i].roffs] = ptrace(PT_READ_U, pid,
(char*)((long)&uframe[reglist[i].roffs] - (long)&corhdr),
0);
}
}
static void
execbkpt(bkptr)
BKPTR bkptr;
{
int bkptloc;
#ifdef DEBUG
print("exbkpt: %d\n", bkptr->count);
#endif
bkptloc = bkptr->loc;
ptrace(PT_WRITE_I, pid, (void*) bkptloc, bkptr->ins);
#ifdef TIOCGETP
ioctl(0, TIOCSETP, &usrtty);
#else
tcsetattr(0, TCSANOW, &usrtty);
#endif
ptrace(PT_STEP, pid, (void*) bkptloc, 0);
bpwait();
chkerr();
ptrace(PT_WRITE_I, pid, (void*) bkptloc, BPT);
bkptr->flag = BKPTSET;
}
int
runpcs(runmode, execsig)
{
int rc = 0;
register BKPTR bkpt;
if (adrflg)
userpc = shorten(dot);
print("%s: running\n", symfil);
while (loopcnt-- > 0) {
#ifdef DEBUG
print("\ncontinue %d %d\n", userpc, execsig);
#endif
#ifdef TIOCGETP
ioctl(0, TIOCSETP, &usrtty);
#else
tcsetattr(0, TCSANOW, &usrtty);
#endif
ptrace (runmode, pid, (void*) userpc, execsig);
bpwait();
chkerr();
readregs();
/* look for bkpt */
if (signo == 0 && (bkpt = scanbkpt(uframe[FRAME_PC] - 2))) {
/* stopped at bkpt */
userpc = uframe[FRAME_PC] = bkpt->loc;
if (bkpt->flag == BKPTEXEC ||
((bkpt->flag = BKPTEXEC, command(bkpt->comm, ':')) &&
--bkpt->count))
{
execbkpt(bkpt);
execsig = 0;
loopcnt++;
userpc = 1;
} else {
bkpt->count = bkpt->initcnt;
rc = 1;
}
} else {
rc = 0;
execsig = signo;
userpc = 1;
}
}
return(rc);
}
void
endpcs()
{
register BKPTR bkptr;
if (pid) {
ptrace(PT_KILL, pid, 0, 0);
pid = 0;
userpc = 1;
for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) {
if (bkptr->flag) {
bkptr->flag = BKPTSET;
}
}
}
}
static void
doexec()
{
char *argl[MAXARG];
char args[LINSIZ];
char *p, **ap, *filnam;
ap = argl;
p = args;
*ap++ = symfil;
do {
if (rdc() == EOR)
break;
/*
* If we find an argument beginning with a `<' or a `>', open
* the following file name for input and output, respectively
* and back the argument collocation pointer, p, back up.
*/
*ap = p;
while (lastc != EOR && lastc != SP && lastc != TB) {
*p++ = lastc;
readchar();
}
*p++ = 0;
filnam = *ap + 1;
if (**ap == '<') {
close(0);
if (open(filnam, 0) < 0) {
print("%s: cannot open\n", filnam);
exit(0);
}
p = *ap;
} else if (**ap == '>') {
close(1);
if (open(filnam, O_CREAT | O_WRONLY, 0666) < 0) {
print("%s: cannot create\n", filnam);
exit(0);
}
p = *ap;
} else {
ap++;
}
} while (lastc != EOR);
*ap++ = 0;
execv(symfil, argl);
}
void
setup()
{
close(fsym);
fsym = -1;
pid = fork();
if (pid == 0) {
ptrace(PT_TRACE_ME, 0, 0, 0);
signal(SIGINT, sigint);
signal(SIGQUIT, sigqit);
doexec();
exit(0);
} else if (pid == -1) {
error(NOFORK);
} else {
bpwait();
readregs();
lp[0] = EOR;
lp[1] = 0;
fsym = open(symfil, wtflag);
if (errflg) {
print("%s: cannot execute\n", symfil);
endpcs();
error((char *)0);
}
}
}
BKPTR
scanbkpt(adr)
{
register BKPTR bkptr;
for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) {
if (bkptr->flag && bkptr->loc == adr)
break;
}
return bkptr;
}
void
delbp()
{
register BKPTR bkptr;
for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) {
if (bkptr->flag)
del1bp(bkptr);
}
}
void
del1bp(bkptr)
BKPTR bkptr;
{
ptrace(PT_WRITE_I, pid, (void*) bkptr->loc, bkptr->ins);
}
void
setbp()
{
register BKPTR bkptr;
for (bkptr=bkpthead; bkptr; bkptr=bkptr->nxtbkpt) {
if (bkptr->flag)
set1bp(bkptr);
}
}
void
set1bp(bkptr)
BKPTR bkptr;
{
register int a;
a = bkptr->loc;
bkptr->ins = ptrace(PT_READ_I, pid, (void*) a, 0);
ptrace(PT_WRITE_I, pid, (void*) a, BPT);
if (errno) {
print("cannot set breakpoint: ");
psymoff(leng(bkptr->loc), ISYM, "\n");
}
}
+127
View File
@@ -0,0 +1,127 @@
#include "defs.h"
#include <fcntl.h>
#include <strings.h>
u_int *uframe = UFRAME;
char *symfil = "a.out";
char *corfil = "core";
static long bss;
static int
getfile(filnam, cnt)
char *filnam;
int cnt;
{
register int f;
if (strcmp("-", filnam) == 0)
return -1;
f = open(filnam, wtflag);
if (f < 0 && argcount > cnt) {
if (wtflag)
f = open(filnam, O_CREAT | O_TRUNC | wtflag, 644);
if (f < 0)
print("cannot open `%s'\n", filnam);
}
return f;
}
void
setsym()
{
struct exec hdr;
bzero(&txtmap, sizeof (txtmap));
fsym = getfile(symfil, 1);
txtmap.ufd = fsym;
if (read(fsym, &hdr, sizeof (hdr)) >= (int)sizeof (hdr)) {
magic = hdr.a_magic;
txtsiz = hdr.a_text;
datsiz = hdr.a_data;
bss = hdr.a_bss;
entrypt = hdr.a_entry;
txtmap.f1 = N_TXTOFF(hdr);
symoff = N_SYMOFF(hdr);
switch (magic) {
case OMAGIC: /* 0407 */
txtmap.b1 = USER_DATA_START;
txtmap.e1 = USER_DATA_START + txtsiz + datsiz;
txtmap.b2 = txtmap.b1;
txtmap.e2 = txtmap.e1;
txtmap.f2 = txtmap.f1;
break;
default:
magic = 0;
txtsiz = 0;
datsiz = 0;
bss = 0;
entrypt = 0;
}
datbas = txtmap.b2;
symINI(&hdr);
}
if (magic == 0) {
txtmap.e1 = maxfile;
}
}
void
setcor()
{
fcor = getfile(corfil, 2);
datmap.ufd = fcor;
if (read(fcor, corhdr, sizeof corhdr) == sizeof corhdr) {
if (! kernel) {
txtsiz = ((struct user*)corhdr)->u_tsize;
datsiz = ((struct user*)corhdr)->u_dsize;
stksiz = ((struct user*)corhdr)->u_ssize;
datmap.f1 = USIZE;
datmap.b2 = USER_DATA_END - stksiz;
datmap.e2 = USER_DATA_END;
} else {
datsiz = datsiz + bss;
stksiz = (long) USIZE;
datmap.f1 = 0;
datmap.b2 = 0140000L;
datmap.e2 = 0140000L + USIZE;
}
switch (magic) {
case OMAGIC: /* 0407 */
datmap.b1 = USER_DATA_START;
datmap.e1 = USER_DATA_START + txtsiz + datsiz;
if (kernel) {
datmap.f2 = (long)corhdr[KA6] * 0100L;
} else {
datmap.f2 = USIZE + txtsiz + datsiz;
}
break;
default:
magic = 0;
datmap.b1 = 0;
datmap.e1 = maxfile;
datmap.f1 = 0;
datmap.b2 = 0;
datmap.e2 = 0;
datmap.f2 = 0;
}
datbas = datmap.b1;
if (! kernel && magic) {
/* User's frame pointer in user's address space. */
register u_int frame;
frame = (long) ((struct user*)corhdr)->u_frame;
frame -= KERNEL_DATA_END - USIZE;
if (frame > 0 && frame < USIZE && ! (frame & 3)) {
/* User's frame pointer in adb address space. */
uframe = (u_int*) &corhdr[frame >> 2];
}
}
} else {
datmap.e1 = maxfile;
}
}
+349
View File
@@ -0,0 +1,349 @@
/*
* Symbol table and file handling service routines
*/
#include "defs.h"
#include <fcntl.h>
#ifdef CROSS
# include </usr/include/stdio.h>
#else
# include <stdio.h>
#endif
struct SYMcache {
char *name;
int used;
struct SYMbol *syment;
};
#ifndef NUM_SYMS_CACHE
#define NUM_SYMS_CACHE 50
#endif
static struct SYMcache symcache[NUM_SYMS_CACHE];
static struct SYMcache *endcache = &symcache[NUM_SYMS_CACHE];
static struct SYMbol *symtab;
static FILE *strfp;
static int symcnt;
static int symnum;
u_int
findsym(svalue, type)
u_int svalue;
int type;
{
long diff, value, symval;
register struct SYMbol *sp;
struct SYMbol *symsav = 0;
int i;
value = svalue;
diff = 0xffffff;
if (type != NSYM && symnum) {
for (i = 0, sp = symtab; diff && i < symnum; i++, sp++) {
if (SYMTYPE(sp->type) == type) {
symval = leng(sp->value);
if ((value - symval) < diff && value >= symval) {
diff = value - symval;
symsav = sp;
}
}
}
}
if (symsav)
symcnt = symsav - symtab;
symbol = symsav;
return shorten(diff);
}
void
valpr(v, idsp)
{
u_int d;
d = findsym(v, idsp);
if (d < maxoff) {
print("%s", cache_sym(symbol));
if (d)
print(OFFMODE, d);
}
}
int
localsym(cframe)
long cframe;
{
int symflg;
while (symget() && localok && (symflg = (int)symbol->type) != N_FN &&
*no_cache_sym(symbol) != '~')
{
if (symflg >= 2 && symflg <= 4) {
localval = symbol->value;
return TRUE;
} else if (symflg == 1) {
localval = leng(shorten(cframe) + symbol->value);
return TRUE;
} else if (symflg == 20 && lastframe) {
localval = leng(lastframe + 2 * symbol->value - 10);
return TRUE;
}
}
return FALSE;
}
void
psymoff(v, type, s)
long v;
int type;
char *s;
{
u_int w;
w = findsym(shorten(v), type);
if (w >= maxoff) {
print(LPRMODE, v);
} else {
print("%s", cache_sym(symbol));
if (w) {
print(OFFMODE, w);
}
}
print(s);
}
/*
* sequential search through table
*/
void
symset()
{
symcnt = -1;
}
struct SYMbol *
symget()
{
if (symcnt >= symnum || ! symnum)
return NULL;
symcnt++;
symbol = &symtab[symcnt];
return symbol;
}
static unsigned int
fgetword (f)
register FILE *f;
{
register unsigned int h;
h = getc (f);
h |= getc (f) << 8;
h |= getc (f) << 16;
h |= getc (f) << 24;
return h;
}
/*
* Read a symbol table entry.
* Return a number of bytes read, or -1 on EOF.
* Format of symbol record:
* 1 byte: length of name in bytes
* 1 byte: type of symbol (N_UNDF, N_ABS, N_TEXT, etc)
* 4 bytes: value
* N bytes: name
*/
static int
fgetsym (fi, name, value, type)
register FILE *fi;
register char *name;
unsigned *value, *type;
{
register int len;
unsigned nbytes;
len = getc (fi);
if (len <= 0)
return -1;
*type = getc (fi);
*value = fgetword (fi);
nbytes = len + 6;
if (name) {
while (len-- > 0)
*name++ = getc (fi);
*name = '\0';
} else
fseek (fi, len, SEEK_CUR);
return nbytes;
}
/*
* This only _looks_ expensive ;-) The extra scan over the symbol
* table allows us to cut down the amount of memory needed.
* A late addition to the program excludes register symbols - the assembler
* generates *lots* of them and they're useless to us.
*/
void
symINI(ex)
struct exec *ex;
{
register struct SYMbol *sp;
register FILE *fp;
int nused, globals_only = 0;
u_int value, type;
fp = fopen(symfil, "r");
strfp = fp;
if (! fp)
return;
fcntl(fileno(fp), F_SETFD, 1);
/* First pass: count the number of symbols used. */
fseek(fp, symoff, SEEK_SET);
nused = 0;
symnum = ex->a_syms;
while (symnum > 0) {
int nbytes = fgetsym(fp, 0, &value, &type);
if (nbytes <= 0)
break;
symnum -= nbytes;
nused++;
}
symtab = (struct SYMbol *)malloc(nused * sizeof (struct SYMbol));
if (! symtab) {
/* Second pass: count only globals. */
fseek(fp, symoff, SEEK_SET);
globals_only = 1;
nused = 0;
symnum = ex->a_syms;
while (symnum > 0) {
int nbytes = fgetsym(fp, 0, &value, &type);
if (nbytes <= 0)
break;
symnum -= nbytes;
if (! (type & N_EXT))
continue;
nused++;
}
symtab = (struct SYMbol *)malloc(nused * sizeof(struct SYMbol));
if (! symtab) {
print("%s: no memory for %d symbols\n", myname, nused);
symnum = 0;
return;
}
}
/* Third pass: read the symbols. */
fseek(fp, symoff, SEEK_SET);
sp = symtab;
symnum = ex->a_syms;
while (symnum > 0) {
char name[256];
int nbytes = fgetsym(fp, name, &value, &type);
if (nbytes <= 0)
break;
symnum -= nbytes;
if (globals_only && ! (type & N_EXT))
continue;
sp->value = value;
sp->type = type;
sp->sname = strdup(name);
sp++;
//print("%s = %08x (%x)\n", name, value, type);
}
symnum = nused;
#if 1
//printf("file '%s'\n", symfil);
printf("text=%u data=%u bss=%u symoff=%u syms=%u\n",
ex->a_text, ex->a_data, ex->a_bss, (unsigned) symoff, ex->a_syms);
printf("%d symbols loaded\n", nused);
#endif
if (globals_only)
print("%s: could only do global symbols\n", myname);
symset();
}
/*
* Look in the cache for a symbol in memory. If it is not found use
* the least recently used entry in the cache and update it with the
* symbol name.
*/
char *
cache_sym(symp)
register struct SYMbol *symp;
{
register struct SYMcache *sc = symcache;
struct SYMcache *current;
int lru;
if (! symp)
return "?";
for (current = NULL, lru = 30000 ; sc < endcache; sc++) {
if (sc->syment == symp) {
sc->used++;
if (sc->used >= 30000)
sc->used = 10000;
return sc->name;
}
if (sc->used < lru) {
lru = sc->used;
current = sc;
}
}
sc = current;
sc->used = 1;
sc->syment = symp;
sc->name = symp->sname;
return sc->name;
}
/*
* We take a look in the cache but do not update the cache on a miss.
* This is done when scanning thru the symbol table (printing all externals
* for example) for large numbers of symbols which probably won't be
* used again any time soon.
*/
char *
no_cache_sym(symp)
register struct SYMbol *symp;
{
register struct SYMcache *sc = symcache;
if (! symp)
return "?";
for ( ; sc < endcache; sc++) {
if (sc->syment == symp) {
sc->used++;
if (sc->used >= 30000)
sc->used = 10000;
return sc->name;
}
}
return symp->sname;
}
/*
* Looks in the cache for a match by string value rather than string
* file offset.
*/
struct SYMbol *
cache_by_string(str)
char *str;
{
register struct SYMcache *sc;
for (sc = symcache; sc < endcache; sc++) {
if (! sc->name)
continue;
if (eqsym(sc->name, str, '_'))
break;
}
if (sc < endcache) {
sc->used++;
if (sc->used > 30000)
sc->used = 10000;
return sc->syment;
}
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#==========================================
# Makefile: makefile for adc-demo
# Copyright 2012 Majenko Technolohies
# (matt@majenko.co.uk
# Last Modified: 29/01/2012
#==========================================
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
OBJS = adc-demo.o
SRCS = adc-demo.c
LIBS += -lcurses -ltermcap -lc
all: adc-demo
adc-demo: ${OBJS}
${CC} ${LDFLAGS} -o adc-demo.elf ${OBJS} ${LIBS}
${OBJDUMP} -S adc-demo.elf > adc-demo.dis
${SIZE} adc-demo.elf
${ELF2AOUT} adc-demo.elf $@
clean:
-rm -f adc-demo ${OBJS} adc-demo.elf adc-demo.dis
install: all
install adc-demo $(DESTDIR)/bin/
+93
View File
@@ -0,0 +1,93 @@
#include <stdlib.h>
#include <stdio.h>
#include <curses.h>
#include <fcntl.h>
#include <sys/adc.h>
#include <unistd.h>
WINDOW *win;
struct channel {
int fd;
int value;
char enabled;
};
int main(int argc, char **argv)
{
struct channel channels[16];
char temp[100];
int i;
long flags;
int value;
const char opts[] = ":d:";
int opt;
unsigned long delay = 100;
for(i=0; i<16; i++)
channels[i].enabled = 1;
while((opt = getopt(argc, argv, opts)) != -1)
{
switch(opt)
{
case 'd':
delay = atol(optarg);
break;
}
}
for(i=0; i<16; i++)
{
if(channels[i].enabled == 1)
{
sprintf(temp,"/dev/adc%d",i);
channels[i].fd = open(temp,O_RDWR);
if(!channels[i].fd)
{
printf("Error: unable to open %s\n",temp);
exit(10);
}
fcntl(channels[i].fd,F_GETFD,&flags);
flags |= O_NONBLOCK;
fcntl(channels[i].fd,F_SETFD,&flags);
}
}
win = initscr();
clear();
while(1)
{
clear();
for(i=0; i<16; i++)
{
if(channels[i].enabled == 1)
{
if(read(channels[i].fd,temp,20))
{
if(sscanf(temp,"%d",&value))
{
channels[i].value = value;
}
}
sprintf(temp,"adc%-2d %4d ",i,channels[i].value);
mvwaddstr(win,i,0,temp);
for(value=0; value<channels[i].value>>4; value++)
{
mvwaddch(win,i,value+11,'=');
}
// clrtoeol();
}
}
refresh();
usleep(delay * 1000);
}
for(i=0; i<16; i++)
{
close(channels[i].fd);
}
endwin();
}
+34
View File
@@ -0,0 +1,34 @@
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
CFLAGS += -Werror -Wall
SRCS = append.c ar.c archive.c contents.c delete.c extract.c misc.c \
move.c print.c replace.c strmode.c
OBJS = append.o ar.o archive.o contents.o delete.o extract.o \
misc.o move.o print.o replace.o strmode.o
MAN = ar.1.0 ar.5.0
MANSRC = ar.1 ar.5
all: ar $(MAN)
ar: ${OBJS}
${CC} ${LDFLAGS} -o ar.elf ${OBJS} ${LIBS}
${OBJDUMP} -S ar.elf > ar.dis
${SIZE} ar.elf
${ELF2AOUT} ar.elf $@ && rm ar.elf
ar.1.0: ar.1
${MANROFF} $< > $@
ar.5.0: ar.5.5
${MANROFF} $< > $@
clean:
rm -f *.o *.0 *.elf ${MAN} ar *.elf *.dis tags *~
install: all
install ar $(DESTDIR)/bin/
cp ar.1.0 $(DESTDIR)/share/man/cat1/ar.0
cp ar.5.0 $(DESTDIR)/share/man/cat5/ar.0
+101
View File
@@ -0,0 +1,101 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <stdio.h>
# include <time.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/select.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <stdint.h>
# include <string.h>
# include <errno.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/file.h>
# include <stdio.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
#endif
#include "archive.h"
#include "extern.h"
extern char *archive; /* archive name */
extern int errno;
/*
* append --
* Append files to the archive - modifies original archive or creates
* a new archive if named archive does not exist.
*/
int
append(argv)
char **argv;
{
register int fd, afd;
register char *file;
struct stat sb;
CF cf;
int eval;
afd = open_archive(O_CREAT|O_RDWR);
if (lseek(afd, (off_t)0, L_XTND) == (off_t)-1)
error(archive);
/* Read from disk, write to an archive; pad on write. */
SETCF(0, 0, afd, archive, WPAD);
for (eval = 0; (file = *argv++) != 0;) {
if ((fd = open(file, O_RDONLY)) < 0) {
(void)fprintf(stderr,
"ar: %s: %s.\n", file, strerror(errno));
eval = 1;
continue;
}
if (options & AR_V)
(void)printf("q - %s\n", file);
cf.rfd = fd;
cf.rname = file;
put_arobj(&cf, &sb);
(void)close(fd);
}
close_archive(afd);
return(eval);
}
+255
View File
@@ -0,0 +1,255 @@
.\" Copyright (c) 1990 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" Hugh Smith at The University of Guelph.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)ar.1 6.10 (Berkeley) 3/21/91
.\"
.TH AR 1 "March 21, 1991"
.AT 3
.SH NAME
ar \- create and maintain library archives
.SH SYNOPSIS
.nf
.ft B
ar -d [-Tv] archive file ...
ar -m [-Tv] archive file ...
ar -m [-abiTv] position archive file ...
ar -p [-Tv] archive [file ...]
ar -q [-cTv] archive file ...
ar -r [-cuTv] archive file ...
ar -r [-abciuTv] position archive file ...
ar -t [-Tv] archive [file ...]
ar -x [-ouTv] archive [file ...]
.fi
.ft R
.SH DESCRIPTION
The
.I ar
utility creates and maintains groups of files combined into an archive.
Once an archive has been created, new files can be added and existing
files can be extracted, deleted, or replaced.
.PP
Files are named in the archive by a single component, i.e., if a file
referenced by a path containing a slash (``/'') is archived it will be
named by the last component of that path.
When matching paths listed on the command line against file names stored
in the archive, only the last component of the path will be compared.
.PP
All informational and error messages use the path listed on the command
line, if any was specified, otherwise the name in the archive is used.
If multiple files in the archive have the same name, and paths are listed
on the command line to ``select'' archive files for an operation, only the
.B first
file with a matching name will be selected.
.PP
The normal use of
.I ar
is for the creation and maintenance of libraries suitable for use with
the loader (see
.IR ld (1))
although it is not restricted to this purpose.
The options are as follows:
.TP
\-a
A positioning modifier used with the options \-r and \-m.
The files are entered or moved
.B after
the archive member
.IR position ,
which must be specified.
.TP
\-b
A positioning modifier used with the options \-r and \-m.
The files are entered or moved
.B before
the archive member
.IR position ,
which must be specified.
.TP
\-c
Whenever an archive is created, an informational message to that effect
is written to standard error.
If the \-c option is specified,
.I ar
creates the archive silently.
.TP
\-d
Delete the specified archive files.
.TP
\-i
Identical to the \-b option.
.TP
\-m
Move the specified archive files within the archive.
If one of the options \-a, \-b or \-i are specified, the files are moved
before or after the
.I position
file in the archive.
If none of those options are specified, the files are moved
to the end of the archive.
.TP
\-o
Set the access and modification times of extracted files to the
modification time of the file when it was entered into the archive.
This will fail if the user is not the owner of the extracted file
or the super-user.
.TP
\-p
Write the contents of the specified archive files to the standard output.
If no files are specified, the contents of all the files in the archive
are written in the order they appear in the archive.
.TP
\-q
(Quickly) append the specified files to the archive.
If the archive does not exist a new archive file is created.
Much faster than the \-r option, when creating a large archive
piece-by-piece, as no checking is done to see if the files already
exist in the archive.
.TP
\-r
Replace or add the specified files to the archive.
If the archive does not exist a new archive file is created.
Files that replace existing files do not change the order of the files
within the archive.
New files are appended to the archive unless one of the options \-a, \-b
or \-i is specified.
.TP
\-T
Select and/or name archive members using only the first fifteen characters
of the archive member or command line file name.
The historic archive format had sixteen bytes for the name, but some
historic archiver and loader implementations were unable to handle names
that used the entire space.
This means that file names that are not unique in their first fifteen
characters can subsequently be confused.
A warning message is printed to the standard error output if any file
names are truncated.
(See
.IR ar (5)
for more information.)
.TP
\-t
List the specified files in the order in which they appear in the archive,
each on a separate line.
If no files are specified, all files in the archive are listed.
.TP
\-u
Update files.
When used with the \-r option, files in the archive will be replaced
only if the disk file has a newer modification time than the file in
the archive.
When used with the \-x option, files in the archive will be extracted
only if the archive file has a newer modification time than the file
on disk.
.TP
\-v
Provide verbose output.
When used with the \-d, \-m, \-q or \-x options,
.I ar
gives a file-by-file description of the archive modification.
This description consists of three, white-space separated fields: the
option letter, a dash (``-'') and the file name.
When used with the \-r option,
.I ar
displays the description as above, but the initial letter is an ``a'' if
the file is added to the archive and an ``r'' if the file replaces a file
already in the archive.
.IP
When used with the \-p option,
the name of each printed file is written to the standard output before
the contents of the file, preceded by a single newline character, and
followed by two newline characters, enclosed in less-than (``<'') and
greater-than (``>'') characters.
.IP
When used with the \-t option,
.I ar
displays an ``ls -l'' style listing of information about the members of
the archive.
This listing consists of eight, white-space separated fields:
the file permissions (see
.IR strmode (3)),
the decimal user and group ID's, separated by a single slash (``/''),
the file size (in bytes), the file modification time (in the
.IR date (1)
format ``%b %e %H:%M %Y''), and the name of the file.
.TP
\-x
Extract the specified archive members into the files named by the command
line arguments.
If no members are specified, all the members of the archive are extracted into
the current directory.
.IP
If the file does not exist, it is created; if it does exist, the owner
and group will be unchanged.
The file access and modification times are the time of the extraction
(but see the \-o option).
The file permissions will be set to those of the file when it was entered
into the archive; this will fail if the user is not the owner of the
extracted file or the super-user.
.PP
The
.I ar
utility exits 0 on success, and >0 if an error occurs.
.SH ENVIRONMENT
.TP
TMPDIR
The pathname of the directory to use when creating temporary files.
.SH FILES
.TP 14
/tmp
default temporary file directory
.TP 14
ar.XXXXXX
temporary file names
.SH COMPATIBILITY
By default,
.I ar
writes archives that may be incompatible with historic archives, as
the format used for storing archive members with names longer than
fifteen characters has changed.
This implementation of
.I ar
is backward compatible with previous versions of
.I ar
in that it can read and write (using the \-T option) historic archives.
The \-T option is provided for compatibility only, and will be deleted
in a future release.
See
.IR ar (5)
for more information.
.SH STANDARDS
The
.I ar
utility is expected to offer a superset of the POSIX 1003.2 functionality.
.SH "SEE ALSO"
ld(1), ranlib(1), strmode(3), ar(5)
+143
View File
@@ -0,0 +1,143 @@
.\" Copyright (c) 1990, 1991 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)ar.5.5 6.3 (Berkeley) 5/10/91
.\" 6.3.1 (2.11BSD) 9/24/93
.\"
.TH AR 5 "September 24, 1993"
.UC 2
.SH NAME
ar \- archive (library) file format
.SH SYNOPSIS
#include <ar.h>
.SH DESCRIPTION
The archive command
.I ar
combines several files into one.
Archives are mainly used as libraries of object files intended to be
loaded using the link-editor
.IR ld (1).
.PP
A file created with
.I ar
begins with the ``magic'' string "!<arch>\en".
The rest of the archive is made up of objects, each of which is composed
of a header for a file, a possible file name, and the file contents.
The header is portable between machine architectures, and, if the file
contents are printable, the archive is itself printable.
.PP
The header is made up of six variable length
ASCII
fields, followed by a
two character trailer.
The fields are the object name (16 characters), the file last modification
time (12 characters), the user and group id's (each 6 characters), the file
mode (8 characters) and the file size (10 characters).
All numeric fields are in decimal, except for the file mode which is in
octal.
.PP
The modification time is the file
.I st_mtime
field, i.e.,
.B CUT
seconds since
the epoch.
The user and group id's are the file
.I st_uid
and
.I st_gid
fields.
The file mode is the file
.I st_mode
field.
The file size is the file
.I st_size
field.
The two-byte trailer is the string "\`\en".
.PP
Only the name field has any provision for overflow.
If any file name is more than 16 characters in length or contains an
embedded space, the string "#1/" followed by the
ASCII
length of the
name is written in the name field.
The file size (stored in the archive header) is incremented by the length
of the name.
The name is then written immediately following the archive header.
.PP
Any unused characters in any of these fields are written as space
characters.
If any fields are their particular maximum number of characters in
length, there will be no separation between the fields.
.PP
Objects in the archive are always an even number of bytes long; files
which are an odd number of bytes long are padded with a newline (``\en'')
character, although the size in the header does not reflect this.
.SH SEE ALSO
.IR ar (1),
.IR stat (2)
.SH HISTORY
There have been at least four
.I ar
formats.
The first was denoted by the leading ``magic'' number 0177555 (stored as
type int).
These archives were almost certainly created on a 16-bit machine, and
contain headers made up of five fields.
The fields are the object name (8 characters), the file last modification
time (type long), the user id (type char), the file mode (type char) and
the file size (type unsigned int).
Files were padded to an even number of bytes.
.PP
The second was denoted by the leading ``magic'' number 0177545 (stored as
type int).
These archives may have been created on either 16 or 32-bit machines, and
contain headers made up of six fields.
The fields are the object name (14 characters), the file last modification
time (type long), the user and group id's (each type char), the file mode
(type int) and the file size (type long).
Files were padded to an even number of bytes.
For more information on converting from this format see
.IR arcv (8).
.PP
The current archive format (without support for long character names and
names with embedded spaces) was introduced in 4.0BSD.
The headers were the same as the current format, with the exception that
names longer than 16 characters were truncated, and names with embedded
spaces (and often trailing spaces) were not supported.
It has been extended for these reasons,
as described above.
This format is under development.
.SH COMPATIBILITY
No archive format is currently specified by any standard.
AT&T System V UNIX
has historically distributed archives in a different format from
all of the above.
+255
View File
@@ -0,0 +1,255 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <stdint.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <errno.h>
# include <getopt.h>
#else
# include <sys/param.h>
# include <sys/dir.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
#endif
#include <ar.h>
#include "archive.h"
#include "extern.h"
extern int errno;
CHDR chdr;
unsigned options;
char *archive, *envtmp, *posarg, *posname;
static void
usage()
{
(void)fprintf(stderr, "Usage:\n");
(void)fprintf(stderr, " ar -d [-Tv] archive file ...\n");
(void)fprintf(stderr, " ar -m [-Tv] archive file ...\n");
(void)fprintf(stderr, " ar -m [-abiTv] position archive file ...\n");
(void)fprintf(stderr, " ar -p [-Tv] archive [file ...]\n");
(void)fprintf(stderr, " ar -q [-cTv] archive file ...\n");
(void)fprintf(stderr, " ar -r [-cuTv] archive file ...\n");
(void)fprintf(stderr, " ar -r [-abciuTv] position archive file ...\n");
(void)fprintf(stderr, " ar -t [-Tv] archive [file ...]\n");
(void)fprintf(stderr, " ar -x [-ouTv] archive [file ...]\n");
(void)fprintf(stderr, "Commands:\n");
(void)fprintf(stderr, " -d Delete file(s) from the archive\n");
(void)fprintf(stderr, " -m Move file(s) in the archive\n");
(void)fprintf(stderr, " -p Print file(s) found in the archive\n");
(void)fprintf(stderr, " -q Quick append file(s) to the archive\n");
(void)fprintf(stderr, " -r Replace existing or insert new file(s) into the archive\n");
(void)fprintf(stderr, " -t Display contents of archive\n");
(void)fprintf(stderr, " -x Extract file(s) from the archive\n");
(void)fprintf(stderr, "Modifiers:\n");
(void)fprintf(stderr, " -a Put file(s) after [member-name]\n");
(void)fprintf(stderr, " -b, -i Put file(s) before [member-name]\n");
(void)fprintf(stderr, " -c Do not warn if the library had to be created\n");
(void)fprintf(stderr, " -u Only replace files that are newer than current archive contents\n");
(void)fprintf(stderr, " -o Preserve original dates\n");
(void)fprintf(stderr, " -T Make a thin archive\n");
(void)fprintf(stderr, " -v Be verbose\n");
exit(1);
}
static void
badoptions(arg)
char *arg;
{
(void)fprintf(stderr,
"ar: illegal option combination for %s.\n", arg);
usage();
}
/*
* main --
* main basically uses getopt to parse options and calls the appropriate
* functions. Some hacks that let us be backward compatible with 4.3 ar
* option parsing and sanity checking.
*/
int
main(argc, argv)
int argc;
char **argv;
{
extern int optind;
int c;
char *p;
int (*fcall)() = 0;
if (argc < 3)
usage();
/*
* Historic versions didn't require a '-' in front of the options.
* Fix it, if necessary.
*/
if (*argv[1] != '-') {
if (!(p = malloc((unsigned)(strlen(argv[1]) + 2)))) {
(void)fprintf(stderr, "ar: %s.\n", strerror(errno));
exit(1);
}
*p = '-';
(void)strcpy(p + 1, argv[1]);
argv[1] = p;
}
while ((c = getopt(argc, argv, "abcdilmopqrTtuvx")) != EOF) {
switch(c) {
case 'a':
options |= AR_A;
break;
case 'b':
case 'i':
options |= AR_B;
break;
case 'c':
options |= AR_C;
break;
case 'd':
options |= AR_D;
fcall = delete;
break;
case 'l': /* not documented, compatibility only */
envtmp = ".";
break;
case 'm':
options |= AR_M;
fcall = move;
break;
case 'o':
options |= AR_O;
break;
case 'p':
options |= AR_P;
fcall = print;
break;
case 'q':
options |= AR_Q;
fcall = append;
break;
case 'r':
options |= AR_R;
fcall = replace;
break;
case 'T':
options |= AR_TR;
break;
case 't':
options |= AR_T;
fcall = contents;
break;
case 'u':
options |= AR_U;
break;
case 'v':
options |= AR_V;
break;
case 'x':
options |= AR_X;
fcall = extract;
break;
default:
usage();
}
}
argv += optind;
argc -= optind;
/* One of -dmpqrtx required. */
if (!(options & (AR_D|AR_M|AR_P|AR_Q|AR_R|AR_T|AR_X))) {
(void)fprintf(stderr,
"ar: one of options -dmpqrtx is required.\n");
usage();
}
/* Only one of -a and -bi allowed. */
if (options & AR_A && options & AR_B) {
(void)fprintf(stderr,
"ar: only one of -a and -[bi] options allowed.\n");
usage();
}
/* -ab require a position argument. */
if (options & (AR_A|AR_B)) {
if (!(posarg = *argv++)) {
(void)fprintf(stderr,
"ar: no position operand specified.\n");
usage();
}
posname = rname(posarg);
}
/* -d only valid with -Tv. */
if (options & AR_D && options & ~(AR_D|AR_TR|AR_V))
badoptions("-d");
/* -m only valid with -abiTv. */
if (options & AR_M && options & ~(AR_A|AR_B|AR_M|AR_TR|AR_V))
badoptions("-m");
/* -p only valid with -Tv. */
if (options & AR_P && options & ~(AR_P|AR_TR|AR_V))
badoptions("-p");
/* -q only valid with -cTv. */
if (options & AR_Q && options & ~(AR_C|AR_Q|AR_TR|AR_V))
badoptions("-q");
/* -r only valid with -abcuTv. */
if (options & AR_R && options & ~(AR_A|AR_B|AR_C|AR_R|AR_U|AR_TR|AR_V))
badoptions("-r");
/* -t only valid with -Tv. */
if (options & AR_T && options & ~(AR_T|AR_TR|AR_V))
badoptions("-t");
/* -x only valid with -ouTv. */
if (options & AR_X && options & ~(AR_O|AR_U|AR_TR|AR_V|AR_X))
badoptions("-x");
if (!(archive = *argv++)) {
(void)fprintf(stderr, "ar: no archive specified.\n");
usage();
}
/* -dmqr require a list of archive elements. */
if (options & (AR_D|AR_M|AR_Q|AR_R) && !*argv) {
(void)fprintf(stderr, "ar: no archive members specified.\n");
usage();
}
if (! fcall)
exit(1);
exit((*fcall)(argv));
}
+346
View File
@@ -0,0 +1,346 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <time.h>
# include <fcntl.h>
# include <stdint.h>
# include <sys/file.h>
# include <sys/stat.h>
# include <stdio.h>
# include <string.h>
# include <strings.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/file.h>
# include <stdio.h>
# include <string.h>
# include <strings.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
#endif
#include <ar.h>
#include "archive.h"
#include "extern.h"
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
extern int errno;
typedef struct ar_hdr HDR;
static char hb[sizeof(HDR) + 1]; /* real header */
int
open_archive(mode)
int mode;
{
int created, fd, nr;
char buf[SARMAG];
created = 0;
if (mode & O_CREAT) {
mode |= O_EXCL;
fd = open(archive, mode, 0666);
if (fd >= 0) {
/* POSIX.2 puts create message on stderr. */
if (!(options & AR_C))
(void)fprintf(stderr,
"ar: creating archive %s.\n", archive);
created = 1;
goto opened;
}
if (errno != EEXIST)
error(archive);
mode &= ~O_EXCL;
}
fd = open(archive, mode, 0666);
if (fd < 0)
error(archive);
/*
* Attempt to place a lock on the opened file - if we get an
* error then someone is already working on this library (or
* it's going across NFS).
*/
opened: if (flock(fd, LOCK_EX|LOCK_NB) && errno != EOPNOTSUPP)
error(archive);
/*
* If not created, O_RDONLY|O_RDWR indicates that it has to be
* in archive format.
*/
if (!created &&
((mode & 3) == O_RDONLY || (mode & 3) == O_RDWR)) {
if ((nr = read(fd, buf, SARMAG) != SARMAG)) {
if (nr >= 0)
badfmt();
error(archive);
} else if (bcmp(buf, ARMAG, SARMAG))
badfmt();
} else if (write(fd, ARMAG, SARMAG) != SARMAG)
error(archive);
return(fd);
}
void
close_archive(fd)
int fd;
{
(void)close(fd); /* Implicit unlock. */
}
/* Convert ar header field to an integer. */
#define AR_ATOI(from, to, len, base) { \
bcopy(from, buf, len); \
buf[len] = '\0'; \
to = strtol(buf, (char **)NULL, base); \
}
/*
* get_arobj --
* read the archive header for this member
*/
int
get_arobj(fd)
int fd;
{
struct ar_hdr *hdr;
register int len, nr;
register char *p;
char buf[20];
nr = read(fd, hb, sizeof(HDR));
if (nr != sizeof(HDR)) {
if (!nr)
return(0);
if (nr < 0)
error(archive);
badfmt();
}
hdr = (struct ar_hdr *)hb;
if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
badfmt();
/* Convert the header into the internal format. */
#define DECIMAL 10
#define OCTAL 8
AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), DECIMAL);
AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), DECIMAL);
AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), DECIMAL);
AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), OCTAL);
AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), DECIMAL);
/* Leading spaces should never happen. */
if (hdr->ar_name[0] == ' ')
badfmt();
/*
* Long name support. Set the "real" size of the file, and the
* long name flag/size.
*/
if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) {
chdr.lname = len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1);
if (len <= 0 || len > MAXNAMLEN)
badfmt();
nr = read(fd, chdr.name, (size_t)len);
if (nr != len) {
if (nr < 0)
error(archive);
badfmt();
}
chdr.name[len] = 0;
chdr.size -= len;
} else {
chdr.lname = 0;
bcopy(hdr->ar_name, chdr.name, sizeof(hdr->ar_name));
/* Strip trailing spaces, null terminate. */
for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
*++p = '\0';
}
return(1);
}
static int already_written;
/*
* copy_ar --
* Copy size bytes from one file to another - taking care to handle the
* extra byte (for odd size files) when reading archives and writing an
* extra byte if necessary when adding files to archive. The length of
* the object is the long name plus the object itself; the variable
* already_written gets set if a long name was written.
*
* The padding is really unnecessary, and is almost certainly a remnant
* of early archive formats where the header included binary data which
* a PDP-11 required to start on an even byte boundary. (Or, perhaps,
* because 16-bit word addressed copies were faster?) Anyhow, it should
* have been ripped out long ago.
*/
void
copy_ar(cfp, size)
CF *cfp;
off_t size;
{
static char pad = '\n';
off_t sz;
register int from, nr, nw, off, to;
#ifdef pdp11
char buf[2*1024];
#else
char buf[8*1024];
#endif
if (!(sz = size))
return;
from = cfp->rfd;
to = cfp->wfd;
while (sz) {
nr = read(from, buf, sz < sizeof(buf) ? sz : sizeof(buf));
if (nr <= 0)
break;
sz -= nr;
for (off = 0; off < nr; nr -= off, off += nw)
if ((nw = write(to, buf + off, (size_t)nr)) < 0)
error(cfp->wname);
}
if (sz) {
if (nr == 0)
badfmt();
error(cfp->rname);
}
if (cfp->flags & RPAD && size & 1 && (nr = read(from, buf, 1)) != 1) {
if (nr == 0)
badfmt();
error(cfp->rname);
}
if (cfp->flags & WPAD && (size + already_written) & 1 &&
write(to, &pad, 1) != 1)
error(cfp->wname);
}
/*
* put_arobj --
* Write an archive member to a file.
*/
void
put_arobj(cfp, sb)
CF *cfp;
struct stat *sb;
{
register int lname;
register char *name;
struct ar_hdr *hdr;
off_t size;
/*
* If passed an sb structure, reading a file from disk. Get stat(2)
* information, build a name and construct a header. (Files are named
* by their last component in the archive.) If not, then just write
* the last header read.
*/
if (sb) {
name = rname(cfp->rname);
(void)fstat(cfp->rfd, sb);
/*
* If not truncating names and the name is too long or contains
* a space, use extended format 1.
*/
lname = strlen(name);
if (options & AR_TR) {
if (lname > OLDARMAXNAME) {
(void)fflush(stdout);
(void)fprintf(stderr,
"ar: warning: %s truncated to %.*s\n",
name, OLDARMAXNAME, name);
(void)fflush(stderr);
}
(void)sprintf(hb, HDR3, name, sb->st_mtime, sb->st_uid,
sb->st_gid, sb->st_mode, (long) sb->st_size, ARFMAG);
lname = 0;
} else if (lname > sizeof(hdr->ar_name) || index(name, ' '))
(void)sprintf(hb, HDR1, AR_EFMT1, lname, sb->st_mtime,
sb->st_uid, sb->st_gid, sb->st_mode,
(long) sb->st_size + lname, ARFMAG);
else {
lname = 0;
(void)sprintf(hb, HDR2, name, sb->st_mtime, sb->st_uid,
sb->st_gid, sb->st_mode, (long) sb->st_size, ARFMAG);
}
size = sb->st_size;
} else {
lname = chdr.lname;
name = chdr.name;
size = chdr.size;
}
if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR))
error(cfp->wname);
if (lname) {
if (write(cfp->wfd, name, (size_t)lname) != lname)
error(cfp->wname);
already_written = lname;
}
copy_ar(cfp, size);
already_written = 0;
}
/*
* skip_arobj -
* Skip over an object -- taking care to skip the pad bytes.
*/
void
skip_arobj(fd)
int fd;
{
off_t len;
len = chdr.size + (chdr.lname & 1);
if (lseek(fd, len, SEEK_CUR) == (off_t)-1)
error(archive);
}
+128
View File
@@ -0,0 +1,128 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# ifdef __linux__
# undef O_CREAT
# define O_CREAT 00000100
# undef O_EXCL
# define O_EXCL 00000200
# undef O_NOCTTY
# define O_NOCTTY 00000400
# undef O_TRUNC
# define O_TRUNC 00001000
# endif
# ifndef MAXNAMLEN
# define MAXNAMLEN 63
# endif
# ifndef MAXPATHLEN
# define MAXPATHLEN 256
# endif
# ifndef _PATH_ARTMP
# define _PATH_ARTMP "/tmp/ar.XXXXXX"
# endif
#endif
/* Ar(1) options. */
#define AR_A 0x0001
#define AR_B 0x0002
#define AR_C 0x0004
#define AR_D 0x0008
#define AR_M 0x0010
#define AR_O 0x0020
#define AR_P 0x0040
#define AR_Q 0x0080
#define AR_R 0x0100
#define AR_T 0x0200
#define AR_TR 0x0400
#define AR_U 0x0800
#define AR_V 0x1000
#define AR_X 0x2000
extern unsigned options;
/* Set up file copy. */
#define SETCF(from, fromname, to, toname, pad) { \
cf.rfd = from; \
cf.rname = fromname; \
cf.wfd = to; \
cf.wname = toname; \
cf.flags = pad; \
}
/* File copy structure. */
typedef struct {
int rfd; /* read file descriptor */
char *rname; /* read name */
int wfd; /* write file descriptor */
char *wname; /* write name */
#define NOPAD 0x00 /* don't pad */
#define RPAD 0x01 /* pad on reads */
#define WPAD 0x02 /* pad on writes */
unsigned flags; /* pad flags */
} CF;
/* Header structure internal format. */
typedef struct {
off_t size; /* size of the object in bytes */
long date; /* date */
int lname; /* size of the long name in bytes */
int gid; /* group */
int uid; /* owner */
unsigned short mode; /* permissions */
char name[MAXNAMLEN + 1]; /* name */
} CHDR;
/* Header format strings. */
#define HDR1 "%s%-13d%-12ld%-6u%-6u%-8o%-10ld%2s"
#define HDR2 "%-16.16s%-12ld%-6u%-6u%-8o%-10ld%2s"
#define OLDARMAXNAME 15
#define HDR3 "%-16.15s%-12ld%-6u%-6u%-8o%-10ld%2s"
void close_archive();
void skip_arobj();
void copy_ar();
int get_arobj();
int open_archive();
void put_arobj();
int delete (register char **argv);
int move (register char **argv);
int print (register char **argv);
int append (register char **argv);
int replace (register char **argv);
int contents (register char **argv);
int extract (register char **argv);
+118
View File
@@ -0,0 +1,118 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/fcntl.h>
# include <stdio.h>
# include <stdint.h>
# include <string.h>
# include <time.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/time.h>
# include <stdio.h>
# include <string.h>
# include <fcntl.h>
# include <tzfile.h>
#endif
#include <ar.h>
#include "archive.h"
#include "extern.h"
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
/*
* contents --
* Handles t[v] option - opens the archive and then reads headers,
* skipping member contents.
*/
int
contents(argv)
register char **argv;
{
register int afd, all;
struct tm *tp;
char *file, buf[25];
afd = open_archive(O_RDONLY);
for (all = !*argv; get_arobj(afd);) {
if (all)
file = chdr.name;
else if (!(file = files(argv)))
goto next;
if (options & AR_V) {
(void)strmode(chdr.mode, buf);
(void)printf("%s %6d/%-6d %8ld ",
buf + 1, chdr.uid, chdr.gid, (long) chdr.size);
tp = localtime(&chdr.date);
#ifdef bloat
(void)strftime(buf, sizeof(buf), "%b %e %H:%M %Y", tp);
(void)printf("%s %s\n", buf, file);
#else
{
/*
* Bloat avoidance alert! Doing the date this way saves dragging in not only
* strftime() but mktime() and ctime() for a savings of over 8kb. God, those
* leap seconds or whatever don't come cheap, the old (4.3BSD) timezone code
* was big enough but this new stuff (posix?) is horrid.
*/
static char *months[] = {"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
(void)printf("%s %02d %02d:%02d %4d %s\n",
months[tp->tm_mon], tp->tm_mday, tp->tm_hour,
tp->tm_min, 1900+tp->tm_year, file);
}
#endif
} else
(void)printf("%s\n", file);
if (!all && !*argv)
break;
next: skip_arobj(afd);
}
close_archive(afd);
if (*argv) {
orphans(argv);
return(1);
}
return(0);
}
+102
View File
@@ -0,0 +1,102 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/select.h>
# include <sys/fcntl.h>
# include <stdint.h>
# include <stdio.h>
# include <unistd.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/file.h>
# include <stdio.h>
# include <unistd.h>
# include <fcntl.h>
#endif
#include <ar.h>
#include "archive.h"
#include "extern.h"
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
extern char *tname; /* temporary file "name" */
/*-
* delete --
* Deletes named members from the archive.
*/
int
delete(argv)
register char **argv;
{
CF cf;
off_t size;
int afd, tfd;
char *file;
afd = open_archive(O_RDWR);
tfd = tmp();
/* Read and write to an archive; pad on both. */
SETCF(afd, archive, tfd, tname, RPAD|WPAD);
while (get_arobj(afd)) {
if (*argv && (file = files(argv))) {
if (options & AR_V)
(void)printf("d - %s\n", file);
skip_arobj(afd);
continue;
}
put_arobj(&cf, (struct stat *)NULL);
}
size = lseek(tfd, (off_t)0, SEEK_CUR);
(void)lseek(tfd, (off_t)0, SEEK_SET);
(void)lseek(afd, (off_t)SARMAG, SEEK_SET);
SETCF(tfd, tname, afd, archive, NOPAD);
copy_ar(&cf, size);
(void)close(tfd);
(void)ftruncate(afd, size + SARMAG);
close_archive(afd);
if (*argv) {
orphans(argv);
return(1);
}
return(0);
}
+41
View File
@@ -0,0 +1,41 @@
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
void badfmt();
void error();
void orphans();
int compare();
int tmp();
char *files();
char *rname();
void strmode();
+137
View File
@@ -0,0 +1,137 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/select.h>
# include <sys/stat.h>
# include <sys/time.h>
# include <sys/fcntl.h>
# include <stdint.h>
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <errno.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/time.h>
# include <stdio.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
#endif
#include <string.h>
#include "archive.h"
#include "extern.h"
extern int errno;
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
/*
* extract --
* Extract files from the named archive - if member names given only
* extract those members otherwise extract all members. If 'o' option
* selected modify date of newly created file to be same as archive
* members date otherwise date is time of extraction. Does not modify
* archive.
*/
int
extract(argv)
char **argv;
{
register int afd, all, tfd;
struct timeval tv[2];
struct stat sb;
CF cf;
char *file;
tv[0].tv_usec = tv[1].tv_usec = 0;
afd = open_archive(O_RDONLY);
/* Read from an archive, write to disk; pad on read. */
SETCF(afd, archive, 0, 0, RPAD);
for (all = !*argv; get_arobj(afd);) {
if (all)
file = chdr.name;
else if (!(file = files(argv))) {
skip_arobj(afd);
continue;
}
if (options & AR_U && !stat(file, &sb) &&
sb.st_mtime > chdr.date)
continue;
if ((tfd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0200)) < 0) {
(void)fprintf(stderr, "ar: %s: %s.\n",
file, strerror(errno));
skip_arobj(afd);
continue;
}
if (options & AR_V)
(void)printf("x - %s\n", file);
cf.wfd = tfd;
cf.wname = file;
copy_ar(&cf, chdr.size);
if (fchmod(tfd, (short)chdr.mode)) {
(void)fprintf(stderr, "ar: %s: chmod: %s\n",
file, strerror(errno));
}
if (options & AR_O) {
tv[0].tv_sec = tv[1].tv_sec = chdr.date;
if (utimes(file, tv)) {
(void)fprintf(stderr, "ar: %s: utimes: %s\n",
file, strerror(errno));
}
}
(void)close(tfd);
if (!all && !*argv)
break;
}
close_archive(afd);
if (*argv) {
orphans(argv);
return(1);
}
return(0);
}
+164
View File
@@ -0,0 +1,164 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/select.h>
# include <sys/time.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <stdint.h>
# include <unistd.h>
# include <errno.h>
#else
# include <sys/param.h>
# include <sys/dir.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
# include <signal.h>
# include <paths.h>
#endif
#include "archive.h"
#include "extern.h"
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
char *tname = "temporary file"; /* temporary file "name" */
int
tmp()
{
extern char *envtmp;
#ifndef CROSS
sigset_t set, oset;
#endif
static int first;
static const char *artmp = _PATH_ARTMP;
int fd;
char path[MAXPATHLEN];
if (!first && !envtmp) {
envtmp = (char *)getenv("TMPDIR");
first = 1;
}
if (envtmp) {
strcpy(path, envtmp);
strcat(path, strrchr (artmp, '/'));
} else {
strcpy(path, artmp);
}
#ifndef CROSS
sigfillset(&set);
(void)sigprocmask(SIG_BLOCK, &set, &oset);
#endif
fd = mkstemp(path);
if (fd == -1)
error(tname);
(void)unlink(path);
#ifndef CROSS
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
#endif
return(fd);
}
/*
* files --
* See if the current file matches any file in the argument list; if it
* does, remove it from the argument list.
*/
char *
files(argv)
char **argv;
{
register char **list;
char *p;
for (list = argv; *list; ++list)
if (compare(*list)) {
p = *list;
while ((list[0] = list[1]) != 0)
list++;
return(p);
}
return(NULL);
}
void
orphans(argv)
char **argv;
{
for (; *argv; ++argv)
(void)fprintf(stderr,
"ar: %s: not found in archive.\n", *argv);
}
char *
rname(path)
char *path;
{
register char *ind;
ind = strrchr(path, '/');
return(ind ? ind + 1 : path);
}
int
compare(dest)
char *dest;
{
if (options & AR_TR)
return(!strncmp(chdr.name, rname(dest), OLDARMAXNAME));
return(!strcmp(chdr.name, rname(dest)));
}
void
badfmt()
{
errno = EINVAL;
error(archive);
}
void
error(name)
char *name;
{
(void)fprintf(stderr, "ar: %s: %s\n", name, strerror(errno));
exit(1);
}
+147
View File
@@ -0,0 +1,147 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/select.h>
# include <sys/fcntl.h>
# include <stdio.h>
# include <stdint.h>
# include <unistd.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/file.h>
# include <stdio.h>
# include <unistd.h>
# include <fcntl.h>
#endif
#include <ar.h>
#include "archive.h"
#include "extern.h"
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
extern char *tname; /* temporary file "name" */
/*
* move --
* Change location of named members in archive - if 'b' or 'i' option
* selected then named members are placed before 'posname'. If 'a'
* option selected members go after 'posname'. If no options, members
* are moved to end of archive.
*/
int
move(argv)
char **argv;
{
extern char *posarg, *posname; /* positioning file names */
CF cf;
off_t size, tsize;
int afd, curfd, mods, tfd1, tfd2, tfd3;
char *file;
afd = open_archive(O_RDWR);
mods = options & (AR_A|AR_B);
tfd1 = tmp(); /* Files before key file. */
tfd2 = tmp(); /* Files selected by user. */
tfd3 = tmp(); /* Files after key file. */
/*
* Break archive into three parts -- selected entries and entries
* before and after the key entry. If positioning before the key,
* place the key at the beginning of the after key entries and if
* positioning after the key, place the key at the end of the before
* key entries. Put it all back together at the end.
*/
/* Read and write to an archive; pad on both. */
SETCF(afd, archive, 0, tname, RPAD|WPAD);
for (curfd = tfd1; get_arobj(afd);) {
if (*argv && (file = files(argv))) {
if (options & AR_V)
(void)printf("m - %s\n", file);
cf.wfd = tfd2;
put_arobj(&cf, (struct stat *)NULL);
continue;
}
if (mods && compare(posname)) {
mods = 0;
if (options & AR_B)
curfd = tfd3;
cf.wfd = curfd;
put_arobj(&cf, (struct stat *)NULL);
if (options & AR_A)
curfd = tfd3;
} else {
cf.wfd = curfd;
put_arobj(&cf, (struct stat *)NULL);
}
}
if (mods) {
(void)fprintf(stderr, "ar: %s: archive member not found.\n",
posarg);
close_archive(afd);
return(1);
}
(void)lseek(afd, (off_t)SARMAG, SEEK_SET);
SETCF(tfd1, tname, afd, archive, NOPAD);
tsize = size = lseek(tfd1, (off_t)0, SEEK_CUR);
(void)lseek(tfd1, (off_t)0, SEEK_SET);
copy_ar(&cf, size);
tsize += size = lseek(tfd2, (off_t)0, SEEK_CUR);
(void)lseek(tfd2, (off_t)0, SEEK_SET);
cf.rfd = tfd2;
copy_ar(&cf, size);
tsize += size = lseek(tfd3, (off_t)0, SEEK_CUR);
(void)lseek(tfd3, (off_t)0, SEEK_SET);
cf.rfd = tfd3;
copy_ar(&cf, size);
(void)ftruncate(afd, tsize + SARMAG);
close_archive(afd);
if (*argv) {
orphans(argv);
return(1);
}
return(0);
}
+93
View File
@@ -0,0 +1,93 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/select.h>
# include <sys/fcntl.h>
# include <stdio.h>
# include <stdint.h>
#else
# include <sys/param.h>
# include <sys/dir.h>
# include <stdio.h>
# include <fcntl.h>
#endif
#include "archive.h"
#include "extern.h"
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
/*
* print --
* Prints archive members on stdout - if member names given only
* print those members, otherwise print all members.
*/
int
print(argv)
char **argv;
{
CF cf;
register int afd, all;
char *file;
afd = open_archive(O_RDONLY);
/* Read from an archive, write to stdout; pad on read. */
SETCF(afd, archive, fileno(stdout), "stdout", RPAD);
for (all = !*argv; get_arobj(afd);) {
if (all)
file = chdr.name;
else if (!(file = files(argv))) {
skip_arobj(afd);
continue;
}
if (options & AR_V) {
(void)printf("\n<%s>\n\n", file);
(void)fflush(stdout);
}
copy_ar(&cf, chdr.size);
if (!all && !*argv)
break;
}
close_archive(afd);
if (*argv) {
orphans(argv);
return(1);
}
return(0);
}
+196
View File
@@ -0,0 +1,196 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Hugh Smith at The University of Guelph.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/select.h>
# include <sys/stat.h>
# include <sys/fcntl.h>
# include <stdio.h>
# include <fcntl.h>
# include <stdint.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
#else
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <sys/file.h>
# include <stdio.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
#endif
#include <ar.h>
#include "archive.h"
#include "extern.h"
extern int errno;
extern CHDR chdr; /* converted header */
extern char *archive; /* archive name */
extern char *tname; /* temporary file "name" */
/*
* replace --
* Replace or add named members to archive. Entries already in the
* archive are swapped in place. Others are added before or after
* the key entry, based on the a, b and i options. If the u option
* is specified, modification dates select for replacement.
*/
int
replace(argv)
char **argv;
{
extern char *posarg, *posname; /* positioning file name */
register char *file;
register int afd, curfd, mods, sfd;
struct stat sb;
CF cf;
off_t size, tsize;
int err, exists, tfd1, tfd2;
err = 0;
/*
* If doesn't exist, simply append to the archive. There's
* a race here, but it's pretty short, and not worth fixing.
*/
exists = !stat(archive, &sb);
afd = open_archive(O_CREAT|O_RDWR);
if (!exists) {
tfd1 = -1;
tfd2 = tmp();
goto append;
}
tfd1 = tmp(); /* Files before key file. */
tfd2 = tmp(); /* Files after key file. */
/*
* Break archive into two parts -- entries before and after the key
* entry. If positioning before the key, place the key at the
* beginning of the after key entries and if positioning after the
* key, place the key at the end of the before key entries. Put it
* all back together at the end.
*/
mods = (options & (AR_A|AR_B));
for (curfd = tfd1; get_arobj(afd);) {
if (*argv && (file = files(argv))) {
if ((sfd = open(file, O_RDONLY)) < 0) {
err = 1;
(void)fprintf(stderr, "ar: %s: %s.\n",
file, strerror(errno));
goto useold;
}
(void)fstat(sfd, &sb);
if (options & AR_U && sb.st_mtime <= chdr.date) {
(void)close(sfd);
goto useold;
}
if (options & AR_V)
(void)printf("r - %s\n", file);
/* Read from disk, write to an archive; pad on write */
SETCF(sfd, file, curfd, tname, WPAD);
put_arobj(&cf, &sb);
(void)close(sfd);
skip_arobj(afd);
continue;
}
if (mods && compare(posname)) {
mods = 0;
if (options & AR_B)
curfd = tfd2;
/* Read and write to an archive; pad on both. */
SETCF(afd, archive, curfd, tname, RPAD|WPAD);
put_arobj(&cf, (struct stat *)NULL);
if (options & AR_A)
curfd = tfd2;
} else {
/* Read and write to an archive; pad on both. */
useold: SETCF(afd, archive, curfd, tname, RPAD|WPAD);
put_arobj(&cf, (struct stat *)NULL);
}
}
if (mods) {
(void)fprintf(stderr, "ar: %s: archive member not found.\n",
posarg);
close_archive(afd);
return(1);
}
/* Append any left-over arguments to the end of the after file. */
append: while ((file = *argv++) != 0) {
if (options & AR_V)
(void)printf("a - %s\n", file);
sfd = open(file, O_RDONLY);
if (sfd < 0) {
err = 1;
(void)fprintf(stderr, "ar: %s: %s.\n",
file, strerror(errno));
continue;
}
(void)fstat(sfd, &sb);
/* Read from disk, write to an archive; pad on write. */
SETCF(sfd, file,
options & (AR_A|AR_B) ? tfd1 : tfd2, tname, WPAD);
put_arobj(&cf, &sb);
(void)close(sfd);
}
(void)lseek(afd, (off_t)SARMAG, SEEK_SET);
SETCF(tfd1, tname, afd, archive, NOPAD);
if (tfd1 != -1) {
tsize = size = lseek(tfd1, (off_t)0, SEEK_CUR);
(void)lseek(tfd1, (off_t)0, SEEK_SET);
copy_ar(&cf, size);
} else
tsize = 0;
tsize += size = lseek(tfd2, (off_t)0, SEEK_CUR);
(void)lseek(tfd2, (off_t)0, SEEK_SET);
cf.rfd = tfd2;
copy_ar(&cf, size);
(void)ftruncate(afd, tsize + SARMAG);
close_archive(afd);
return(err);
}
+146
View File
@@ -0,0 +1,146 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef CROSS
# include <sys/types.h>
# include <sys/stat.h>
#else
# include <sys/types.h>
# include <sys/stat.h>
#endif
void
strmode(mode, p)
register mode_t mode;
register char *p;
{
/* print type */
switch (mode & S_IFMT) {
case S_IFDIR: /* directory */
*p++ = 'd';
break;
case S_IFCHR: /* character special */
*p++ = 'c';
break;
case S_IFBLK: /* block special */
*p++ = 'b';
break;
case S_IFREG: /* regular */
*p++ = '-';
break;
case S_IFLNK: /* symbolic link */
*p++ = 'l';
break;
case S_IFSOCK: /* socket */
*p++ = 's';
break;
#ifdef S_IFIFO
case S_IFIFO: /* fifo */
*p++ = 'p';
break;
#endif
default: /* unknown */
*p++ = '?';
break;
}
/* usr */
if (mode & S_IRUSR)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWUSR)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXUSR | S_ISUID)) {
case 0:
*p++ = '-';
break;
case S_IXUSR:
*p++ = 'x';
break;
case S_ISUID:
*p++ = 'S';
break;
case S_IXUSR | S_ISUID:
*p++ = 's';
break;
}
/* group */
if (mode & S_IRGRP)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWGRP)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXGRP | S_ISGID)) {
case 0:
*p++ = '-';
break;
case S_IXGRP:
*p++ = 'x';
break;
case S_ISGID:
*p++ = 'S';
break;
case S_IXGRP | S_ISGID:
*p++ = 's';
break;
}
/* other */
if (mode & S_IROTH)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWOTH)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXOTH | S_ISVTX)) {
case 0:
*p++ = '-';
break;
case S_IXOTH:
*p++ = 'x';
break;
case S_ISVTX:
*p++ = 'T';
break;
case S_IXOTH | S_ISVTX:
*p++ = 't';
break;
}
*p++ = ' '; /* will be a '+' if ACL's implemented */
*p = '\0';
}
+44
View File
@@ -0,0 +1,44 @@
#
# as - Assembler
# aout - Display information from a.out files
#
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
CFLAGS += -Werror -Wall -Os
LDFLAGS +=
AOUTOBJS = aout.o mips-dis.o
all: as aout
as: as.o
${CC} ${LDFLAGS} -o as.elf as.o ${LIBS}
${OBJDUMP} -S as.elf > as.dis
${SIZE} as.elf
${ELF2AOUT} as.elf $@ && rm as.elf
aout: $(AOUTOBJS)
${CC} ${LDFLAGS} -o aout.elf $(AOUTOBJS) ${LIBS}
${OBJDUMP} -S aout.elf > aout.dis
${SIZE} aout.elf
${ELF2AOUT} aout.elf $@ && rm aout.elf
clean:
rm -f *.o *.0 *.elf as aout tags *~ *.dis tests/*.dis tests/*.gcc-dis tests/*.o
test:
/usr/local/pic32-tools/bin/pic32-as -al example.s
install: all
install as $(DESTDIR)/bin/
install aout $(DESTDIR)/bin/
test.dis-gcc: test.s
$(AS) $< -o test.o
${OBJDUMP} -D test.o > $@
test.dis: test.s as aout
./as $< -o test.o
./aout test.o > $@
+313
View File
@@ -0,0 +1,313 @@
/*
* Utility for displaying a.out object file information.
*
* Copyright (C) 2011 Serge Vakulenko, <serge@vak.ru>
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice appear in all
* copies and that both that the copyright notice and this
* permission notice and warranty disclaimer appear in supporting
* documentation, and that the name of the author not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
*
* The author disclaim all warranties with regard to this
* software, including all implied warranties of merchantability
* and fitness. In no event shall the author be liable for any
* special, indirect or consequential damages or any damages
* whatsoever resulting from loss of use, data or profits, whether
* in an action of contract, negligence or other tortious action,
* arising out of or in connection with the use or performance of
* this software.
*/
#ifdef CROSS
# include <stdio.h>
#else
# include <stdio.h>
#endif
#include <unistd.h>
#include <a.out.h>
#define USER_CODE_START 0x7f008000
struct exec hdr; /* a.out header */
FILE *text, *rel;
int rflag, dflag;
int addr;
extern int print_insn_mips (unsigned memaddr,
unsigned long int word, FILE *stream);
unsigned int fgetword (f)
register FILE *f;
{
register unsigned int h;
h = getc (f);
h |= getc (f) << 8;
h |= getc (f) << 16;
h |= getc (f) << 24;
return h;
}
int fgethdr (text, h)
register FILE *text;
register struct exec *h;
{
h->a_magic = fgetword (text);
h->a_text = fgetword (text);
h->a_data = fgetword (text);
h->a_bss = fgetword (text);
h->a_reltext = fgetword (text);
h->a_reldata = fgetword (text);
h->a_syms = fgetword (text);
h->a_entry = fgetword (text);
return (1);
}
/*
* Read a relocation record: 1 to 6 bytes.
*/
void fgetrel (f, r)
register FILE *f;
register struct reloc *r;
{
r->flags = getc (f);
if ((r->flags & RSMASK) == REXT) {
r->index = getc (f);
r->index |= getc (f) << 8;
r->index |= getc (f) << 16;
}
if ((r->flags & RFMASK) == RHIGH16 ||
(r->flags & RFMASK) == RHIGH16S)
{
r->offset = getc (f);
r->offset |= getc (f) << 8;
}
}
/*
* Read a symbol table entry.
* Return a number of bytes read, or -1 on EOF.
* Format of symbol record:
* 1 byte: length of name in bytes
* 1 byte: type of symbol (N_UNDF, N_ABS, N_TEXT, etc)
* 4 bytes: value
* N bytes: name
*/
int fgetsym (text, name, value, type)
register FILE *text;
register char *name;
unsigned *value;
unsigned *type;
{
register int len;
unsigned nbytes;
len = getc (text);
if (len <= 0)
return -1;
*type = getc (text);
*value = fgetword (text);
nbytes = len + 6;
while (len-- > 0)
*name++ = getc (text);
*name = '\0';
return nbytes;
}
void prrel (r)
register struct reloc *r;
{
printf ("<");
switch (r->flags & RSMASK) {
default: putchar ('?'); break;
case RTEXT: putchar ('t'); break;
case RDATA: putchar ('d'); break;
case RBSS: putchar ('b'); break;
case REXT: printf ("%d", r->index); break;
case RABS: break;
}
switch (r->flags & RFMASK) {
default: putchar ('?'); break;
case RBYTE32: putchar ('b'); break;
case RWORD26: putchar ('j'); break;
case RWORD16: putchar ('w'); break;
case RHIGH16: printf ("u.%x", r->offset); break;
case RHIGH16S: printf ("h.%x", r->offset); break;
case RBYTE16: break;
}
if (r->flags & RGPREL)
putchar ('g');
printf (">");
}
void prtext (n)
register int n;
{
unsigned opcode;
struct reloc relinfo;
while (n--) {
printf (" %8x:", addr);
opcode = fgetword (text);
printf ("\t%08x", opcode);
if (rflag) {
putchar (' ');
fgetrel (rel, &relinfo);
prrel (&relinfo);
}
if (! dflag) {
putchar ('\t');
print_insn_mips (addr, opcode, stdout);
}
putchar ('\n');
/* Next address */
addr += 4;
}
}
void prdata (n)
register int n;
{
struct reloc relinfo;
while (n--) {
printf (" %8x:\t%08x", addr, fgetword (text));
if (rflag) {
putchar (' ');
fgetrel (rel, &relinfo);
prrel (&relinfo);
}
putchar ('\n');
/* Next address */
addr += 4;
}
}
void prsyms (nbytes)
register int nbytes;
{
register int n, c;
unsigned value, type;
char name [256];
while (nbytes > 0) {
n = fgetsym (text, name, &value, &type);
if (n <= 0)
break;
nbytes -= n;
switch (type & N_TYPE) {
case N_ABS: c = 'a'; break;
case N_TEXT: c = 't'; break;
case N_DATA: c = 'd'; break;
case N_BSS: c = 'b'; break;
case N_STRNG: c = 's'; break;
case N_UNDF: c = 'u'; break;
case N_COMM: c = 'c'; break;
case N_FN: c = 'f'; break;
default: c = '?'; break;
}
if (type & N_EXT)
c += 'A' - 'a';
if (c == 'U')
printf (" %c %s\n", c, name);
else
printf (" %08x %c %s\n", value, c, name);
}
}
void disasm (fname)
register char *fname;
{
text = fopen (fname, "r");
if (! text) {
fprintf (stderr, "aout: %s not found\n", fname);
return;
}
if (! fgethdr (text, &hdr) || N_BADMAG (hdr)) {
fprintf (stderr, "aout: %s not an object file\n", fname);
return;
}
if (rflag) {
if (hdr.a_magic != RMAGIC) {
fprintf (stderr, "aout: %s is not relocatable\n",
fname);
rflag = 0;
} else {
rel = fopen (fname, "r");
if (! rel) {
fprintf (stderr, "aout: %s not found\n", fname);
return;
}
fseek (rel, N_TRELOFF (hdr), 0);
}
}
printf ("File %s:\n", fname);
printf (" a_magic = %08x (%s)\n", hdr.a_magic,
hdr.a_magic == RMAGIC ? "relocatable" :
hdr.a_magic == OMAGIC ? "OMAGIC" :
hdr.a_magic == NMAGIC ? "NMAGIC" : "unknown");
printf (" a_text = %08x (%u bytes)\n", hdr.a_text, hdr.a_text);
printf (" a_data = %08x (%u bytes)\n", hdr.a_data, hdr.a_data);
printf (" a_bss = %08x (%u bytes)\n", hdr.a_bss, hdr.a_bss);
printf (" a_reltext = %08x (%u bytes)\n", hdr.a_reltext, hdr.a_reltext);
printf (" a_reldata = %08x (%u bytes)\n", hdr.a_reldata, hdr.a_reldata);
printf (" a_syms = %08x (%u bytes)\n", hdr.a_syms, hdr.a_syms);
printf (" a_entry = %08x\n", hdr.a_entry);
addr = (hdr.a_magic == RMAGIC) ? 0 : USER_CODE_START;
if (hdr.a_text > 0) {
printf ("\nSection .text:\n");
prtext (hdr.a_text / sizeof(int));
}
if (hdr.a_data > 0) {
printf ("\nSection .data:\n");
if (rflag)
fseek (rel, N_DRELOFF (hdr), 0);
prdata (hdr.a_data / sizeof(int));
}
if (hdr.a_syms > 0) {
printf ("\nSymbols:\n");
fseek (text, N_SYMOFF (hdr), 0);
prsyms (hdr.a_syms);
}
printf ("\n");
}
int main (argc, argv)
register char **argv;
{
int ch;
while ((ch = getopt (argc, argv, "rd")) != EOF)
switch (ch) {
case 'r': /* print relocation info */
rflag++;
break;
case 'd': /* do not disassemble */
dflag++;
break;
default:
usage: fprintf (stderr, "Usage:\n");
fprintf (stderr, " aout [-rd] file...\n");
fprintf (stderr, "Options:\n");
fprintf (stderr, " -r Print relocation info\n");
fprintf (stderr, " -d Do not disassemble\n");
return (1);
}
argc -= optind;
argv += optind;
if (argc <= 0)
goto usage;
for (; argc-- > 0; argv++)
disasm (*argv);
return (0);
}
+2717
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+350
View File
@@ -0,0 +1,350 @@
The PIC32 family instruction set complies with the MIPS32 Release 2
instruction set architecture. Refer to "MIPS32 Architecture for
Programmers Volume II: The MIPS32 Instruction Set" at www.mips.com
for more information.
Instruction Description Function
-------------------------------------------------------------------------------
ADD Integer Add Rd = Rs + Rt
ADDI Integer Add Immediate Rt = Rs + Immed
ADDIU Unsigned Integer Add Immediate Rt = Rs +u Immed
ADDIUPC Unsigned Integer Add Immediate to PC
(MIPS16e only) Rt = PC +u Immed
ADDU Unsigned Integer Add Rd = Rs +u Rt
AND Logical AND Rd = Rs & Rt
ANDI Logical AND Immediate Rt = Rs & Immed[15:0]
B Unconditional Branch
(Assembler idiom for: BEQ r0, r0, offset) PC += (signed)offset
BAL Branch and Link GPR[31] = PC + 8
(Assembler idiom for: BGEZAL r0, offset) PC += (signed)offset
BEQ Branch On Equal if Rs == Rt
PC += (signed)offset
BEQL Branch On Equal Likely if Rs == Rt
PC += (signed)offset
else
Ignore Next Instruction
BGEZ Branch on Greater Than or Equal To Zero if !Rs[31]
PC += (signed)offset
BGEZAL Branch on Greater Than or GPR[31] = PC + 8
Equal To Zero And Link if !Rs[31]
PC += (signed)offset
BGEZALL Branch on Greater Than or GPR[31] = PC + 8
Equal To Zero And Link Likely if !Rs[31]
PC += (signed)offset
else
Ignore Next Instruction
BGEZL Branch on Greater Than or if !Rs[31]
Equal To Zero Likely PC += (signed)offset
else
Ignore Next Instruction
BGTZ Branch on Greater Than Zero if !Rs[31] && Rs != 0
PC += (signed)offset
BGTZL Branch on Greater Than Zero Likely if !Rs[31] && Rs != 0
PC += (signed)offset
else
Ignore Next Instruction
BLEZ Branch on Less Than or Equal to Zero if Rs[31] || Rs == 0
PC += (signed)offset
BLEZL Branch on Less Than or Equal to Zero Likely if Rs[31] || Rs == 0
PC += (signed)offset
else
Ignore Next Instruction
BLTZ Branch on Less Than Zero if Rs[31]
PC += (signed)offset
BLTZAL Branch on Less Than Zero And Link GPR[31] = PC + 8
if Rs[31]
PC += (signed)offset
BLTZALL Branch on Less Than Zero And Link Likely GPR[31] = PC + 8
if Rs[31]
PC += (signed)offset
else
Ignore Next Instruction
BLTZL Branch on Less Than Zero Likely if Rs[31]
PC += (signed)offset
else
Ignore Next Instruction
BNE Branch on Not Equal if Rs != Rt
PC += (signed)offset
BNEL Branch on Not Equal Likely if Rs != Rt
PC += (signed)offset
else
Ignore Next Instruction
BREAK Breakpoint Break Exception
CLO Count Leading Ones Rd = NumLeadingOnes(Rs)
CLZ Count Leading Zeroes Rd = NumLeadingZeroes(Rs)
COP0 Coprocessor 0 Operation See Software User's Manual
DERET Return from Debug Exception PC = DEPC
Exit Debug Mode
DI Atomically Disable Interrupts Rt = Status; Status.IE = 0
DIV Divide LO = (signed)Rs / (signed)Rt
HI = (signed)Rs % (signed)Rt
DIVU Unsigned Divide LO = (uns)Rs / (uns)Rt
HI = (uns)Rs % (uns)Rt
EHB Execution Hazard Barrier Stop instruction execution
until execution hazards
are cleared
EI Atomically Enable Interrupts Rt = Status; StatusIE = 1
ERET Return from Exception if SR[2]
PC = ErrorEPC
SR[2] = 0
else
PC = EPC
SR[1] = 0
LL = 0
EXT Extract Bit Field Rt = ExtractField(Rs, pos, size)
INS Insert Bit Field Rt = InsertField(Rs, Rt, pos, size)
J Unconditional Jump PC = PC[31:28] || offset<<2
JAL Jump and Link GPR[31] = PC + 8
PC = PC[31:28] || offset<<2
JALR Jump and Link Register Rd = PC + 8
PC = Rs
JALR.HB Jump and Link Register with Hazard Barrier Like JALR, but also clears
execution and instruction hazards
JALRC Jump and Link Register Compact - do not Rd = PC + 2
execute instruction in jump delay slot PC = Rs
(MIPS16e only)
JR Jump Register PC = Rs
JR.HB Jump Register with Hazard Barrier Like JR, but also clears execution
and instruction hazards
JRC Jump Register Compact - do not execute PC = Rs
instruction in jump delay slot
(MIPS16e only)
LB Load Byte Rt = (byte)Mem[Rs+offset]
LBU Unsigned Load Byte Rt = (ubyte))Mem[Rs+offset]
LH Load Halfword Rt = (half)Mem[Rs+offset]
LHU Unsigned Load Halfword Rt = (uhalf)Mem[Rs+offset]
LL Load Linked Word Rt = Mem[Rs+offset]
LL = 1
LLAdr = Rs + offset
LUI Load Upper Immediate Rt = immediate << 16
LW Load Word Rt = Mem[Rs+offset]
LWPC Load Word, PC relative Rt = Mem[PC+offset]
LWL Load Word Left See Architecture Reference Manual
LWR Load Word Right See Architecture Reference Manual
MADD Multiply-Add HI | LO += (signed)Rs * (signed)Rt
MADDU Multiply-Add Unsigned HI | LO += (uns)Rs * (uns)Rt
MFC0 Move From Coprocessor 0 Rt = CPR[0, Rd, sel]
MFHI Move From HI Rd = HI
MFLO Move From LO Rd = LO
MOVN Move Conditional on Not Zero if Rt != 0 then
Rd = Rs
MOVZ Move Conditional on Zero if Rt = 0 then
Rd = Rs
MSUB Multiply-Subtract HI | LO -= (signed)Rs * (signed)Rt
MSUBU Multiply-Subtract Unsigned HI | LO -= (uns)Rs * (uns)Rt
MTC0 Move To Coprocessor 0 CPR[0, n, Sel] = Rt
MTHI Move To HI HI = Rs
MTLO Move To LO LO = Rs
MUL Multiply with register write HI | LO = Unpredictable
Rd = ((signed)Rs * (signed)Rt) [31:0]
MULT Integer Multiply HI | LO = (signed)Rs * (signed)Rd
MULTU Unsigned Multiply HI | LO = (uns)Rs * (uns)Rd
NOP No Operation
(Assembler idiom for: SLL r0, r0, r0)
NOR Logical NOR Rd = ~(Rs | Rt)
OR Logical OR Rd = Rs | Rt
ORI Logical OR Immediate Rt = Rs | Immed
RDHWR Read Hardware Register Allows unprivileged access
to registers enabled by
HWREna register
RDPGPR Read GPR from Previous Shadow Set Rt = SGPR[SRSCtl.PSS, Rd]
RESTORE Restore registers and deallocate stack See Architecture Reference Manual
frame (MIPS16eª only)
ROTR Rotate Word Right Rd = Rt[sa-1..0] || Rt[31..sa]
ROTRV Rotate Word Right Variable Rd = Rt[Rs-1..0] || Rt[31..Rs]
SAVE Save registers and allocate stack frame See Architecture Reference Manual
(MIPS16e only)
SB Store Byte (byte)Mem[Rs+offset] = Rt
SC Store Conditional Word if LL = 1
mem[Rs+offset] = Rt
Rt = LL
SDBBP Software Debug Break Point Trap to SW Debug Handler
SEB Sign-Extend Byte Rd = (byte)Rs
SEH Sign-Extend Half Rd = (half)Rs
SH Store Half (half)Mem[Rs+offset] = Rt
SLL Shift Left Logical Rd = Rt << sa
SLLV Shift Left Logical Variable Rd = Rt << Rs[4:0]
SLT Set on Less Than if (signed)Rs < (signed)Rt
Rd = 1
else
Rd = 0
SLTI Set on Less Than Immediate if (signed)Rs < (signed)Immed
Rt = 1
else
Rt = 0
SLTIU Set on Less Than Immediate Unsigned if (uns)Rs < (uns)Immed
Rt = 1
else
Rt = 0
SLTU Set on Less Than Unsigned if (uns)Rs < (uns)Immed
Rd = 1
else
Rd = 0
SRA Shift Right Arithmetic Rd = (signed)Rt >> sa
SRAV Shift Right Arithmetic Variable Rd = (signed)Rt >> Rs[4:0]
SRL Shift Right Logical Rd = (uns)Rt >> sa
SRLV Shift Right Logical Variable Rd = (uns)Rt >> Rs[4:0]
SSNOP Superscalar Inhibit No Operation NOP
SUB Integer Subtract Rt = (signed)Rs - (signed)Rd
SUBU Unsigned Subtract Rt = (uns)Rs - (uns)Rd
SW Store Word Mem[Rs+offset] = Rt
SWL Store Word Left See Architecture Reference Manual
SWR Store Word Right See Architecture Reference Manual
SYNC Synchronize See Software User's Manual
SYSCALL System Call SystemCallException
TEQ Trap if Equal if Rs == Rt
TrapException
TEQI Trap if Equal Immediate if Rs == (signed)Immed
TrapException
TGE Trap if Greater Than or Equal if (signed)Rs >= (signed)Rt
TrapException
TGEI Trap if Greater Than or Equal Immediate if (signed)Rs >= (signed)Immed
TrapException
TGEIU Trap if Greater Than or if (uns)Rs >= (uns)Immed
Equal Immediate Unsigned TrapException
TGEU Trap if Greater Than or Equal Unsigned if (uns)Rs >= (uns)Rt
TrapException
TLT Trap if Less Than if (signed)Rs < (signed)Rt
TrapException
TLTI Trap if Less Than Immediate if (signed)Rs < (signed)Immed
TrapException
TLTIU Trap if Less Than Immediate Unsigned if (uns)Rs < (uns)Immed
TrapException
TLTU Trap if Less Than Unsigned if (uns)Rs < (uns)Rt
TrapException
TNE Trap if Not Equal if Rs != Rt
TrapException
TNEI Trap if Not Equal Immediate if Rs != (signed)Immed
TrapException
WAIT Wait for Interrupts Stall until interrupt occurs
WRPGPR Write to GPR in Previous Shadow Set SGPR[SRSCtl.PSS, Rd] = Rt
WSBH Word Swap Bytes Within Halfwords Rd = Rt23..16 || Rt31..24 ||
Rt7..0 || Rt15..8
XOR Exclusive OR Rd = Rs ^ Rt
XORI Exclusive OR Immediate Rt = Rs ^ (uns)Immed
ZEB Zero-extend byte (MIPS16e only) Rt = (ubyte) Rs
ZEH Zero-extend half (MIPS16e only) Rt = (uhalf) Rs
-------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+224
View File
@@ -0,0 +1,224 @@
/*
* This is the opcodes table for the mips16 processor. The format of
* this table is intentionally identical to the one in mips-opc.c.
* However, the special letters that appear in the argument string are
* different, and the table uses some different flags.
*
* Copyright 1996, 1997, 1998, 2000, 2005, 2006, 2007
* Free Software Foundation, Inc.
* Contributed by Ian Lance Taylor, Cygnus Support
* Adapted for VirtualMIPS by Serge Vakulenko.
*
* This file is part of the virtualmips distribution.
* See LICENSE file for terms of the license.
*/
/* Use some short hand macros to keep down the length of the lines in
the opcodes table. */
#define UBD INSN_UNCOND_BRANCH_DELAY
#define UBR MIPS16_INSN_UNCOND_BRANCH
#define CBR MIPS16_INSN_COND_BRANCH
#define WR_x MIPS16_INSN_WRITE_X
#define WR_y MIPS16_INSN_WRITE_Y
#define WR_z MIPS16_INSN_WRITE_Z
#define WR_T MIPS16_INSN_WRITE_T
#define WR_SP MIPS16_INSN_WRITE_SP
#define WR_31 MIPS16_INSN_WRITE_31
#define WR_Y MIPS16_INSN_WRITE_GPR_Y
#define RD_x MIPS16_INSN_READ_X
#define RD_y MIPS16_INSN_READ_Y
#define RD_Z MIPS16_INSN_READ_Z
#define RD_T MIPS16_INSN_READ_T
#define RD_SP MIPS16_INSN_READ_SP
#define RD_31 MIPS16_INSN_READ_31
#define RD_PC MIPS16_INSN_READ_PC
#define RD_X MIPS16_INSN_READ_GPR_X
#define WR_HI INSN_WRITE_HI
#define WR_LO INSN_WRITE_LO
#define RD_HI INSN_READ_HI
#define RD_LO INSN_READ_LO
#define TRAP INSN_TRAP
#define I1 INSN_ISA1
#define I3 INSN_ISA3
#define I32 INSN_ISA32
#define I64 INSN_ISA64
#define T3 INSN_3900
static const struct mips_opcode mips16_opcodes[] =
{
/* name, args, match, mask, pinfo, pinfo2, membership */
{"nop", "", 0x6500, 0xffff, RD_Z, 0, I1 }, /* move $0,$Z */
{"la", "x,A", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 },
{"addiu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1 },
{"addiu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1 },
{"addiu", "S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 },
{"addiu", "S,S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 },
{"addiu", "x,P,V", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 },
{"addiu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1 },
{"addu", "z,v,y", 0xe001, 0xf803, WR_z|RD_x|RD_y, 0, I1 },
{"addu", "y,x,4", 0x4000, 0xf810, WR_y|RD_x, 0, I1 },
{"addu", "x,k", 0x4800, 0xf800, WR_x|RD_x, 0, I1 },
{"addu", "S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 },
{"addu", "S,S,K", 0x6300, 0xff00, WR_SP|RD_SP, 0, I1 },
{"addu", "x,P,V", 0x0800, 0xf800, WR_x|RD_PC, 0, I1 },
{"addu", "x,S,V", 0x0000, 0xf800, WR_x|RD_SP, 0, I1 },
{"and", "x,y", 0xe80c, 0xf81f, WR_x|RD_x|RD_y, 0, I1 },
{"b", "q", 0x1000, 0xf800, UBR, 0, I1 },
{"beqz", "x,p", 0x2000, 0xf800, CBR|RD_x, 0, I1 },
{"bnez", "x,p", 0x2800, 0xf800, CBR|RD_x, 0, I1 },
{"break", "6", 0xe805, 0xf81f, TRAP, 0, I1 },
{"bteqz", "p", 0x6000, 0xff00, CBR|RD_T, 0, I1 },
{"btnez", "p", 0x6100, 0xff00, CBR|RD_T, 0, I1 },
{"cmpi", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1 },
{"cmp", "x,y", 0xe80a, 0xf81f, WR_T|RD_x|RD_y, 0, I1 },
{"cmp", "x,U", 0x7000, 0xf800, WR_T|RD_x, 0, I1 },
{"dla", "y,E", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 },
{"daddiu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3 },
{"daddiu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3 },
{"daddiu", "S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 },
{"daddiu", "S,S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 },
{"daddiu", "y,P,W", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 },
{"daddiu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3 },
{"daddu", "z,v,y", 0xe000, 0xf803, WR_z|RD_x|RD_y, 0, I3 },
{"daddu", "y,x,4", 0x4010, 0xf810, WR_y|RD_x, 0, I3 },
{"daddu", "y,j", 0xfd00, 0xff00, WR_y|RD_y, 0, I3 },
{"daddu", "S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 },
{"daddu", "S,S,K", 0xfb00, 0xff00, WR_SP|RD_SP, 0, I3 },
{"daddu", "y,P,W", 0xfe00, 0xff00, WR_y|RD_PC, 0, I3 },
{"daddu", "y,S,W", 0xff00, 0xff00, WR_y|RD_SP, 0, I3 },
{"ddiv", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 },
{"ddivu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 },
{"div", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 },
{"divu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 },
{"dmult", "x,y", 0xe81c, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 },
{"dmultu", "x,y", 0xe81d, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 },
{"drem", "0,x,y", 0xe81e, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 },
{"dremu", "0,x,y", 0xe81f, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I3 },
{"dsllv", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3 },
{"dsll", "x,w,[", 0x3001, 0xf803, WR_x|RD_y, 0, I3 },
{"dsll", "y,x", 0xe814, 0xf81f, WR_y|RD_y|RD_x, 0, I3 },
{"dsrav", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3 },
{"dsra", "y,]", 0xe813, 0xf81f, WR_y|RD_y, 0, I3 },
{"dsra", "y,x", 0xe817, 0xf81f, WR_y|RD_y|RD_x, 0, I3 },
{"dsrlv", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3 },
{"dsrl", "y,]", 0xe808, 0xf81f, WR_y|RD_y, 0, I3 },
{"dsrl", "y,x", 0xe816, 0xf81f, WR_y|RD_y|RD_x, 0, I3 },
{"dsubu", "z,v,y", 0xe002, 0xf803, WR_z|RD_x|RD_y, 0, I3 },
{"exit", "L", 0xed09, 0xff1f, TRAP, 0, I1 },
{"exit", "L", 0xee09, 0xff1f, TRAP, 0, I1 },
{"exit", "L", 0xef09, 0xff1f, TRAP, 0, I1 },
{"entry", "l", 0xe809, 0xf81f, TRAP, 0, I1 },
{"extend", "e", 0xf000, 0xf800, 0, 0, I1 },
{"jalr", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 },
{"jalr", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 },
{"jal", "x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 },
{"jal", "R,x", 0xe840, 0xf8ff, UBD|WR_31|RD_x, 0, I1 },
{"jal", "a", 0x1800, 0xfc00, UBD|WR_31, 0, I1 },
{"jalx", "a", 0x1c00, 0xfc00, UBD|WR_31, 0, I1 },
{"jr", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1 },
{"jr", "R", 0xe820, 0xffff, UBD|RD_31, 0, I1 },
{"j", "x", 0xe800, 0xf8ff, UBD|RD_x, 0, I1 },
{"j", "R", 0xe820, 0xffff, UBD|RD_31, 0, I1 },
{"lb", "y,5(x)", 0x8000, 0xf800, WR_y|RD_x, 0, I1 },
{"lbu", "y,5(x)", 0xa000, 0xf800, WR_y|RD_x, 0, I1 },
{"ld", "y,D(x)", 0x3800, 0xf800, WR_y|RD_x, 0, I3 },
{"ld", "y,B", 0xfc00, 0xff00, WR_y|RD_PC, 0, I3 },
{"ld", "y,D(P)", 0xfc00, 0xff00, WR_y|RD_PC, 0, I3 },
{"ld", "y,D(S)", 0xf800, 0xff00, WR_y|RD_SP, 0, I3 },
{"lh", "y,H(x)", 0x8800, 0xf800, WR_y|RD_x, 0, I1 },
{"lhu", "y,H(x)", 0xa800, 0xf800, WR_y|RD_x, 0, I1 },
{"li", "x,U", 0x6800, 0xf800, WR_x, 0, I1 },
{"lw", "y,W(x)", 0x9800, 0xf800, WR_y|RD_x, 0, I1 },
{"lw", "x,A", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 },
{"lw", "x,V(P)", 0xb000, 0xf800, WR_x|RD_PC, 0, I1 },
{"lw", "x,V(S)", 0x9000, 0xf800, WR_x|RD_SP, 0, I1 },
{"lwu", "y,W(x)", 0xb800, 0xf800, WR_y|RD_x, 0, I3 },
{"mfhi", "x", 0xe810, 0xf8ff, WR_x|RD_HI, 0, I1 },
{"mflo", "x", 0xe812, 0xf8ff, WR_x|RD_LO, 0, I1 },
{"move", "y,X", 0x6700, 0xff00, WR_y|RD_X, 0, I1 },
{"move", "Y,Z", 0x6500, 0xff00, WR_Y|RD_Z, 0, I1 },
{"mult", "x,y", 0xe818, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 },
{"multu", "x,y", 0xe819, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 },
{"neg", "x,w", 0xe80b, 0xf81f, WR_x|RD_y, 0, I1 },
{"not", "x,w", 0xe80f, 0xf81f, WR_x|RD_y, 0, I1 },
{"or", "x,y", 0xe80d, 0xf81f, WR_x|RD_x|RD_y, 0, I1 },
{"rem", "0,x,y", 0xe81a, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 },
{"remu", "0,x,y", 0xe81b, 0xf81f, RD_x|RD_y|WR_HI|WR_LO, 0, I1 },
{"sb", "y,5(x)", 0xc000, 0xf800, RD_y|RD_x, 0, I1 },
{"sd", "y,D(x)", 0x7800, 0xf800, RD_y|RD_x, 0, I3 },
{"sd", "y,D(S)", 0xf900, 0xff00, RD_y|RD_PC, 0, I3 },
{"sd", "R,C(S)", 0xfa00, 0xff00, RD_31|RD_PC, 0, I1 },
{"sh", "y,H(x)", 0xc800, 0xf800, RD_y|RD_x, 0, I1 },
{"sllv", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1 },
{"sll", "x,w,<", 0x3000, 0xf803, WR_x|RD_y, 0, I1 },
{"sll", "y,x", 0xe804, 0xf81f, WR_y|RD_y|RD_x, 0, I1 },
{"slti", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1 },
{"slt", "x,y", 0xe802, 0xf81f, WR_T|RD_x|RD_y, 0, I1 },
{"slt", "x,8", 0x5000, 0xf800, WR_T|RD_x, 0, I1 },
{"sltiu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1 },
{"sltu", "x,y", 0xe803, 0xf81f, WR_T|RD_x|RD_y, 0, I1 },
{"sltu", "x,8", 0x5800, 0xf800, WR_T|RD_x, 0, I1 },
{"srav", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1 },
{"sra", "x,w,<", 0x3003, 0xf803, WR_x|RD_y, 0, I1 },
{"sra", "y,x", 0xe807, 0xf81f, WR_y|RD_y|RD_x, 0, I1 },
{"srlv", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1 },
{"srl", "x,w,<", 0x3002, 0xf803, WR_x|RD_y, 0, I1 },
{"srl", "y,x", 0xe806, 0xf81f, WR_y|RD_y|RD_x, 0, I1 },
{"subu", "z,v,y", 0xe003, 0xf803, WR_z|RD_x|RD_y, 0, I1 },
{"sw", "y,W(x)", 0xd800, 0xf800, RD_y|RD_x, 0, I1 },
{"sw", "x,V(S)", 0xd000, 0xf800, RD_x|RD_SP, 0, I1 },
{"sw", "R,V(S)", 0x6200, 0xff00, RD_31|RD_SP, 0, I1 },
{"xor", "x,y", 0xe80e, 0xf81f, WR_x|RD_x|RD_y, 0, I1 },
/* MIPS16e additions */
{"jalrc", "x", 0xe8c0, 0xf8ff, UBR|WR_31|RD_x|TRAP, 0, I32 },
{"jalrc", "R,x", 0xe8c0, 0xf8ff, UBR|WR_31|RD_x|TRAP, 0, I32 },
{"jrc", "x", 0xe880, 0xf8ff, UBR|RD_x|TRAP, 0, I32 },
{"jrc", "R", 0xe8a0, 0xffff, UBR|RD_31|TRAP, 0, I32 },
{"restore", "M", 0x6400, 0xff80, WR_31|RD_SP|WR_SP|TRAP, 0, I32 },
{"save", "m", 0x6480, 0xff80, RD_31|RD_SP|WR_SP|TRAP, 0, I32 },
{"sdbbp", "6", 0xe801, 0xf81f, TRAP, 0, I32 },
{"seb", "x", 0xe891, 0xf8ff, WR_x|RD_x, 0, I32 },
{"seh", "x", 0xe8b1, 0xf8ff, WR_x|RD_x, 0, I32 },
{"sew", "x", 0xe8d1, 0xf8ff, WR_x|RD_x, 0, I64 },
{"zeb", "x", 0xe811, 0xf8ff, WR_x|RD_x, 0, I32 },
{"zeh", "x", 0xe831, 0xf8ff, WR_x|RD_x, 0, I32 },
{"zew", "x", 0xe851, 0xf8ff, WR_x|RD_x, 0, I64 },
};
static const int mips16_num_opcodes =
((sizeof mips16_opcodes) / (sizeof (mips16_opcodes[0])));
#undef UBD
#undef UBR
#undef CBR
#undef WR_x
#undef WR_y
#undef WR_z
#undef WR_T
#undef WR_SP
#undef WR_31
#undef WR_Y
#undef RD_x
#undef RD_y
#undef RD_Z
#undef RD_T
#undef RD_SP
#undef RD_31
#undef RD_PC
#undef RD_X
#undef WR_HI
#undef WR_LO
#undef RD_HI
#undef RD_LO
#undef TRAP
#undef I1
#undef I3
#undef I32
#undef I64
#undef T3
+19
View File
@@ -0,0 +1,19 @@
TOPSRC = $(shell cd ../../../..; pwd)
include $(TOPSRC)/target.mk
CFLAGS += -Wall -Os
TESTS = test1 test2 test3 test4
all: ../as ../aout
for i in $(TESTS); do \
$(AS) $$i.s -o $$i.o; \
$(OBJDUMP) -D $$i.o > $$i.gcc-dis; \
../as $$i.s -o $$i.o; \
../aout -r $$i.o > $$i.dis; \
done
clean:
rm -f *.o *.dis *.gcc-dis
hello.s: hello.c
$(CC) $(CFLAGS) -S $<
+4
View File
@@ -0,0 +1,4 @@
void hello()
{
puts ("Hello, World!\n");
}
+117
View File
@@ -0,0 +1,117 @@
# .set noreorder
add $2, $16, $31
addi $2, $3, 123
addiu $3, $4, 234
addu $2, $31, $17
and $31, $3, $18
andi $4, $5, 345
b .+0x14
bal .-0x28
beq $3, $2, .+4
beql $2, $3, .-8
bgez $4, .+12
bgezal $5, .-16
bgezall $6, .+20
bgezl $7, .-24
bgtz $8, .+28
bgtzl $9, .-32
blez $10, .+36
blezl $11, .-40
bltz $12, .+44
bltzal $13, .-48
bltzall $14, .+52
bltzl $15, .-56
bne $16, $17, .-60
bnel $17, $18, .+64
break 123
clo $3, $2
clz $2, $3
deret
di $4
div $5, $6
divu $6, $7
ehb
ei $8
eret
ext $9, $10, 12, 5
ins $10, $11, 13, 6
j .+0x3c
jal .-0x40
jalr $12, $13
jalr.hb $14, $15
jr $16
jr.hb $17
lb $18, 123($19)
lbu $20, 321($21)
lh $22, 234($23)
lhu $24, 432($25)
ll $26, 468($27)
lui $5, 987
lw $28, 864($29)
lwl $30, 124($31)
lwr $3, 420($2)
madd $3, $4
maddu $5, $6
mfc0 $7, $8, 7
mfhi $9
mflo $10
move $11, $12
movn $19, $31, $4
movz $31, $5, $20
msub $13, $14
msubu $15, $16
mtc0 $17, $18, 5
mthi $19
mtlo $20
mul $6, $21, $31
mult $21, $22
multu $23, $24
nop
nor $22, $31, $7
or $31, $8, $23
ori $5, $6, 456
rdhwr $25, $26
rdpgpr $27, $28
ror $29, $30, 27
rorv $31, $3, $2
sb $3, 123($4)
sc $5, 324($6)
sdbbp 234
seb $7, $8
seh $9, $10
sh $11, 432($12)
sll $13, $14, 15
sllv $15, $16, $17
slt $9, $24, $31
slti $6, $7, 567
sltiu $7, $8, 678
sltu $25, $31, $10
sra $18, $19, 9
srav $20, $21, $22
srl $23, $24, 25
srlv $25, $26, $27
ssnop
sub $31, $11, $26
subu $12, $27, $31
sw $28, 426($29)
swl $30, 123($31)
swr $31, 321($3)
sync 1
syscall 654
teq $2, $3
teqi $4, .+4
tge $5, $6
tgei $7, .-8
tgeiu $8, .+12
tgeu $9, $10
tlt $11, $12
tlti $13, .-16
tltiu $14, .+20
tltu $15, $16
tne $17, $18
tnei $19, .-24
wait 53
wrpgpr $20, $21
wsbh $22, $23
xor $28, $31, $13
xori $8, $9, 789
+37
View File
@@ -0,0 +1,37 @@
.file 1 "hello.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 3
.section .rodata.str1.4,"aMS",@progbits,1
.align 2
.LC0:
.ascii "Hello, World!\012\000"
.section .text.hello,"ax",@progbits
.align 2
.globl hello
.set nomips16
.set nomicromips
.ent hello
.type hello, @function
hello:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
.set noreorder
.set nomacro
# Begin mchp_output_function_prologue
# End mchp_output_function_prologue
lui $4,%hi(.LC0)
j puts
addiu $4,$4,%lo(.LC0)
.set macro
.set reorder
# Begin mchp_output_function_epilogue
# End mchp_output_function_epilogue
.end hello
.size hello, .-hello
.ident "GCC: (chipKIT) 4.5.1 chipKIT Compiler for PIC32 MCUs v1.30-20110506"
# Begin MCHP vector dispatch table
# End MCHP vector dispatch table
# MCHP configuration words
+49
View File
@@ -0,0 +1,49 @@
.file 1 "hello.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 3
.rdata
.align 2
.LC0:
.ascii "Hello, World!\012\000"
.section .text.hello,"ax",@progbits
.align 2
.globl hello
.set nomips16
.set nomicromips
.ent hello
.type hello, @function
hello:
.frame $fp,24,$31 # vars= 0, regs= 2/0, args= 16, gp= 0
.mask 0xc0000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
# Begin mchp_output_function_prologue
# End mchp_output_function_prologue
addiu $sp,$sp,-24
sw $31,20($sp)
sw $fp,16($sp)
move $fp,$sp
lui $2,%hi(.LC0)
addiu $4,$2,%lo(.LC0)
jal puts
nop
move $sp,$fp
lw $31,20($sp)
lw $fp,16($sp)
addiu $sp,$sp,24
j $31
nop
.set macro
.set reorder
# Begin mchp_output_function_epilogue
# End mchp_output_function_epilogue
.end hello
.size hello, .-hello
.ident "GCC: (chipKIT) 4.5.1 chipKIT Compiler for PIC32 MCUs v1.30-20110506"
# Begin MCHP vector dispatch table
# End MCHP vector dispatch table
# MCHP configuration words
+90
View File
@@ -0,0 +1,90 @@
.file 1 "crt0.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 3
.section .text._start,"ax",@progbits
.align 2
.globl _start
.set nomips16
.set nomicromips
.ent _start
.type _start, @function
_start:
.frame $sp,24,$31 # vars= 0, regs= 1/0, args= 16, gp= 0
.mask 0x80000000,-4
.fmask 0x00000000,0
# Begin mchp_output_function_prologue
# End mchp_output_function_prologue
addiu $sp,$sp,-24
sw $31,20($sp)
#APP
# 69 "crt0.c" 1
la $gp, _gp
# 0 "" 2
#NO_APP
.set noreorder
.set nomacro
blez $4,.L2
sw $6,%gp_rel(environ)($28)
.set macro
.set reorder
lw $2,0($5)
beq $2,$0,.L2
sw $2,%gp_rel(__progname)($28)
lb $3,0($2)
.set noreorder
.set nomacro
beq $3,$0,.L2
addiu $2,$2,1
.set macro
.set reorder
li $7,47 # 0x2f
.L4:
.set noreorder
.set nomacro
beql $3,$7,.L3
sw $2,%gp_rel(__progname)($28)
.set macro
.set reorder
.L3:
lb $3,0($2)
.set noreorder
.set nomacro
bne $3,$0,.L4
addiu $2,$2,1
.set macro
.set reorder
.L2:
jal main
.set noreorder
.set nomacro
jal exit
move $4,$2
.set macro
.set reorder
# Begin mchp_output_function_epilogue
# End mchp_output_function_epilogue
.end _start
.size _start, .-_start
.globl __progname
.section .rodata.str1.4,"aMS",@progbits,1
.align 2
.LC0:
.ascii "\000"
.section .sdata.__progname,"aw",@progbits
.align 2
.type __progname, @object
.size __progname, 4
__progname:
.word .LC0
.comm environ,4,4
.ident "GCC: (chipKIT) 4.5.1 chipKIT Compiler for PIC32 MCUs v1.30-20110506"
# Begin MCHP vector dispatch table
# End MCHP vector dispatch table
# MCHP configuration words
+87
View File
@@ -0,0 +1,87 @@
Nov 30, 1979:
Awk has been modified yet again, in an attempt to make
its behavior more rational and predictable in the areas
of initialization, comparison, and type coercion.
Herewith what we believe the current truth to be:
1. Each variable and field can potentially be a string
or a number or both at any time.
When a variable is set by the assignment
v = expr
its type is set to that of expr. (This includes +=, ++, etc.)
An arithmetic expression is of type number, a
concatenation is of type string, and so on.
If the assignment is a simple copy, as in
v1 = v2
then the type of v1 becomes that of v2.
2. In comparisons, if both operands are numeric,
the comparison is made numerically. Otherwise,
operands are coerced to string if necessary, and
the comparison is made on strings.
3. The type of any expression can be coerced to
numeric by subterfuges (kludges?) such as
expr + 0
and to string by
expr ""
(i.e., concatenation with a null string).
4. Uninitialized variables have the numeric value
0 and the string value "". Accordingly, if x is
uninitialized,
if (x) ...
is false, and
if (!x) ...
if (x == 0) ...
if (x == "") ...
are all true. But note that
if (x == "0") ...
is false.
5. The type of a field is determined by context
when possible; for example,
$1++
clearly implies that $1 is to be numeric, and
$1 = $1 "," $2
implies that $1 and $2 are both to be strings.
Coercion will be done as needed.
In contexts where types cannot be reliably determined, e.g.,
if ($1 == $2) ...
the type of each field is determined on input by
inspection. All fields are strings; in addition,
each field that contains only a number (in the
sense of Fortran, say) is also considered numeric.
This ensures (for better or worse) that the test
if ($1 == $2) ...
will succeed on the inputs
0 0.0
100 1e2
+100 100
1e-3 1e-3
and fail on the inputs
(null) 0
(null) 0.0
2E-518 6E-427
as we believe it should.
Fields which are explicitly null have the string
value ""; they are not numeric.
Non-existent fields (i.e., fields past NF) are
treated this way too.
As it is for fields, so it is for array elements
created by split(...).
6. There is no warranty of merchantability nor any warranty
of fitness for a particular purpose nor any other warranty,
either express or implied, as to the accuracy of the
enclosed materials or as to their suitability for any
particular purpose. Accordingly, the AWK Development
Task Force assumes no responsibility for their use by the
recipient. Further, the Task Force assumes no obligation
to furnish any assistance of any kind whatsoever, or to
furnish any additional information or documentation.
+44
View File
@@ -0,0 +1,44 @@
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
CFLAGS += -Werror -Os
YACC = bison -y
YFLAGS = -d
LIBS = -lm -lc
FILES = awk.lx.o b.o main.o tran.o lib.o run.o parse.o proctab.o freeze.o
SOURCE = awk.def.h awk.g.y awk.lx.l b.c lib.c main.c parse.c \
proc.c freeze.c run.c tran.c
awk: $(FILES) awk.g.o
${CC} ${LDFLAGS} -o awk.elf $(FILES) awk.g.o ${LIBS}
${OBJDUMP} -S awk.elf > awk.dis
${SIZE} awk.elf
${ELF2AOUT} awk.elf $@ && rm awk.elf
y.tab.h: awk.g.o
awk.h: y.tab.h
-cmp -s y.tab.h awk.h || cp y.tab.h awk.h
$(FILES): awk.h awk.def.h
token.h: awk.h tokenscript
ex - < tokenscript
install: awk
install awk ${DESTDIR}/bin/
profile: awk.g.o $(FILES) mon.o
cc -p -i awk.g.o $(FILES) mon.o -lm
lint:
lint -spu b.c main.c tran.c run.c lib.c parse.c -lm |\
egrep -v '^(error|free|malloc)'
proctab.c: proc.c token.h awk.h
cc -Wall -Werror -o proc proc.c
./proc > proctab.c
clean:
-rm -f *.o *.tmp awk.lx.c *.out *.elf *.dis y.tab.* awk.h proc proctab.c token.h awk
+99
View File
@@ -0,0 +1,99 @@
CHANGES as of July 12:
1. \ddd allowed in regular expressions.
2. exit <expression> causes the expression to
to be the status return upon completion.
3. a new builtin called "getline" causes the next
input line to be read immediately. Fields, NR, etc.,
are all set, but you are left at exactly the same place
in the awk program. Getline returns 0 for end of file;
1 for a normal record.
CHANGES SINCE MEMO:
Update to TM of Sept 1, 1978:
1. A new form of for loop
for (i in array)
statement
is now available. It provides a way to walk
along the members of an array, most usefully
for associative arrays with non-numeric subscripts.
Elements are accessed in an unpredictable order,
so don't count on anything.
Futhermore, havoc ensues if elements are created
during this operation, or if the index variable
is fiddled.
2. index(s1, s2) returns the position in s1
where s2 first occurs, or 0 if it doesn't.
3. Multi-line records are now supported more
conveniently. If the record separator is null
RS = ""
then a blank line terminates a record, and newline
is a default field separator, along with
blank and tab.
4. The syntax of split has been changed.
n = split(str, arrayname, sep)
splits the string str into the array using
the separator sep (a single character).
If no sep field is given, FS is used instead.
The elements are array[1] ... array[n]; n
is the function value.
5. some minor bugs have been fixed.
IMPLEMENTATION NOTES:
Things to watch out for when trying to make awk:
1. The yacc -d business creates a new file y.tab.h
with the yacc #defines in it. this is compared to
awk.h on each successive compile, and major recompilation
is done only if the files differ. (This permits editing
the grammar file without causing everything in sight
to be recompiled, so long as the definitions don't
change.)
2. The program proc.c is compiled into proc, which
is used to create proctab.c. proctab.c is the
table of function pointers used by run to actually
execute things. Don't try to load proc.c with the
other .c files; it also contains a "main()".
3. Awk uses structure assignment. Be sure your
version of the C compiler has it.
4. The loader flag -lm is used to fetch the standard
math library on the Research system. It is more likely
that you will want to use -lS on yours.
run.c also includes "math.h", which contains sensible
definitions for log(), sqrt(), etc. If you don't have this
include file, comment the line out, and all will be well
anyway.
5. The basic sequence of events (in case make doesn't
seem to do the job) is
yacc -d awk.g.y
cc -O -c y.tab.c
mv y.tab.o awk.g.o
lex awk.lx.l
cc -O -c lex.yy.c
mv lex.yy.o awk.lx.o
cc -O -c b.c
cc -O -c main.c
e - <tokenscript
cc -O -c token.c
cc -O -c tran.c
cc -O -c lib.c
cc -O -c run.c
cc -O -c parse.c
cc -O -c proc.c
cc -o proc proc.c token.o
proc >proctab.c
cc -O -c proctab.c
cc -i -O awk.g.o awk.lx.o b.o main.o token.o tran.o lib.o run.o parse.o proctab.o -lm
+135
View File
@@ -0,0 +1,135 @@
/* awk.def 4.3 83/12/09 */
#define hack int
#define AWKFLOAT float
#define xfree(a) { if(a!=NULL) { yfree(a); a=NULL;} }
#define strfree(a) { if(a!=NULL && a!=EMPTY) { yfree(a);} a=EMPTY; }
#define yfree free
#define isnull(x) ((x) == EMPTY || (x) == NULL)
#ifdef DEBUG
# define dprintf if(dbg)printf
#else
# define dprintf(x1, x2, x3, x4)
#endif
typedef AWKFLOAT awkfloat;
extern char **FS;
extern char **RS;
extern char **ORS;
extern char **OFS;
extern char **OFMT;
extern awkfloat *NR;
extern awkfloat *NF;
extern char **FILENAME;
extern char record[];
extern char EMPTY[];
extern int dbg;
extern int lineno;
extern int errorflag;
extern int donefld; /* 1 if record broken into fields */
extern int donerec; /* 1 if record is valid (no fld has changed */
typedef struct val { /* general value during processing */
char *nval; /* name, for variables only */
char *sval; /* string value */
awkfloat fval; /* value as number */
unsigned tval; /* type info */
struct val *nextval; /* ptr to next if chained */
} cell;
extern cell *symtab[];
cell *setsymtab(), *lookup(), **makesymtab();
extern cell *recloc; /* location of input record */
extern cell *nrloc; /* NR */
extern cell *nfloc; /* NF */
#define STR 01 /* string value is valid */
#define NUM 02 /* number value is valid */
#define FLD 04 /* FLD means don't free string space */
#define CON 010 /* this is a constant */
#define ARR 020 /* this is an array */
awkfloat setfval(), getfval();
char *setsval(), *getsval();
char *tostring(), *tokname();
/* function types */
#define FLENGTH 1
#define FSQRT 2
#define FEXP 3
#define FLOG 4
#define FINT 5
typedef struct {
char otype;
char osub;
cell *optr;
} obj;
#define BOTCH 1
struct nd {
char ntype;
char subtype;
struct nd *nnext;
int nobj;
struct nd *narg[BOTCH]; /* C won't take a zero length array */
};
typedef struct nd node;
extern node *winner;
extern node *nullstat;
/* otypes */
#define OCELL 0
#define OEXPR 1
#define OBOOL 2
#define OJUMP 3
/* cell subtypes */
#define CTEMP 4
#define CNAME 3
#define CVAR 2
#define CFLD 1
#define CCON 0
/* bool subtypes */
#define BTRUE 1
#define BFALSE 2
/* jump subtypes */
#define JEXIT 1
#define JNEXT 2
#define JBREAK 3
#define JCONT 4
/* node types */
#define NVALUE 1
#define NSTAT 2
#define NEXPR 3
#define NPA2 4
typedef obj (*objfunc)();
extern const objfunc proctab[];
extern obj true, false;
extern int pairstack[], paircnt;
#define cantexec(n) (n->ntype == NVALUE)
#define notlegal(n) (n <= FIRSTTOKEN || n >= LASTTOKEN || proctab[n-FIRSTTOKEN]== nullproc)
#define isexpr(n) (n->ntype == NEXPR)
#define isjump(n) (n.otype == OJUMP)
#define isexit(n) (n.otype == OJUMP && n.osub == JEXIT)
#define isbreak(n) (n.otype == OJUMP && n.osub == JBREAK)
#define iscont(n) (n.otype == OJUMP && n.osub == JCONT)
#define isnext(n) (n.otype == OJUMP && n.osub == JNEXT)
#define isstr(n) (n.optr->tval & STR)
#define istrue(n) (n.otype == OBOOL && n.osub == BTRUE)
#define istemp(n) (n.otype == OCELL && n.osub == CTEMP)
#define isfld(n) (!donefld && n.osub==CFLD && n.otype==OCELL && n.optr->nval==EMPTY)
#define isrec(n) (donefld && n.osub==CFLD && n.otype==OCELL && n.optr->nval!=EMPTY)
obj nullproc();
obj relop();
#define MAXSYM 50
#define HAT 0177 /* matches ^ in regular expr */
/* watch out for mach dep */
+274
View File
@@ -0,0 +1,274 @@
/* awk.g.y 4.1 82/05/07 */
%token FIRSTTOKEN /*must be first*/
%token FINAL FATAL
%token LT LE GT GE EQ NE
%token MATCH NOTMATCH
%token APPEND
%token ADD MINUS MULT DIVIDE MOD UMINUS
%token ASSIGN ADDEQ SUBEQ MULTEQ DIVEQ MODEQ
%token JUMP
%token XBEGIN XEND
%token NL
%token PRINT PRINTF SPRINTF SPLIT
%token IF ELSE WHILE FOR IN NEXT EXIT BREAK CONTINUE
%token PROGRAM PASTAT PASTAT2
%right ASGNOP
%left BOR
%left AND
%left NOT
%left NUMBER VAR ARRAY FNCN SUBSTR LSUBSTR INDEX
%left GETLINE
%nonassoc RELOP MATCHOP
%left OR
%left STRING DOT CCL NCCL CHAR
%left '(' '^' '$'
%left CAT
%left '+' '-'
%left '*' '/' '%'
%left STAR PLUS QUEST
%left POSTINCR PREINCR POSTDECR PREDECR INCR DECR
%left FIELD INDIRECT
%token LASTTOKEN /* has to be last */
%{
#include "awk.def.h"
#ifndef DEBUG
# define PUTS(x)
#endif
%}
%%
program:
begin pa_stats end { if (errorflag==0) winner = (node *)stat3(PROGRAM, $1, $2, $3); }
| error { yyclearin; yyerror("bailing out"); }
;
begin:
XBEGIN '{' stat_list '}' { PUTS("XBEGIN list"); $$ = $3; }
| begin NL
| { PUTS("empty XBEGIN"); $$ = (hack)nullstat; }
;
end:
XEND '{' stat_list '}' { PUTS("XEND list"); $$ = $3; }
| end NL
| { PUTS("empty END"); $$ = (hack)nullstat; }
;
compound_conditional:
conditional BOR conditional { PUTS("cond||cond"); $$ = op2(BOR, $1, $3); }
| conditional AND conditional { PUTS("cond&&cond"); $$ = op2(AND, $1, $3); }
| NOT conditional { PUTS("!cond"); $$ = op1(NOT, $2); }
| '(' compound_conditional ')' { $$ = $2; }
;
compound_pattern:
pattern BOR pattern { PUTS("pat||pat"); $$ = op2(BOR, $1, $3); }
| pattern AND pattern { PUTS("pat&&pat"); $$ = op2(AND, $1, $3); }
| NOT pattern { PUTS("!pat"); $$ = op1(NOT, $2); }
| '(' compound_pattern ')' { $$ = $2; }
;
conditional:
expr { PUTS("expr"); $$ = op2(NE, $1, valtonode(lookup("$zero&null", symtab, 0), CCON)); }
| rel_expr { PUTS("relexpr"); }
| lex_expr { PUTS("lexexpr"); }
| compound_conditional { PUTS("compcond"); }
;
else:
ELSE optNL { PUTS("else"); }
;
field:
FIELD { PUTS("field"); $$ = valtonode($1, CFLD); }
| INDIRECT term { PUTS("ind field"); $$ = op1(INDIRECT, $2); }
;
if:
IF '(' conditional ')' optNL { PUTS("if(cond)"); $$ = $3; }
;
lex_expr:
expr MATCHOP regular_expr { PUTS("expr~re"); $$ = op2($2, $1, makedfa($3)); }
| '(' lex_expr ')' { PUTS("(lex_expr)"); $$ = $2; }
;
var:
NUMBER {PUTS("number"); $$ = valtonode($1, CCON); }
| STRING { PUTS("string"); $$ = valtonode($1, CCON); }
| VAR { PUTS("var"); $$ = valtonode($1, CVAR); }
| VAR '[' expr ']' { PUTS("array[]"); $$ = op2(ARRAY, $1, $3); }
| field
;
term:
var
| GETLINE { PUTS("getline"); $$ = op1(GETLINE, 0); }
| FNCN { PUTS("func");
$$ = op2(FNCN, $1, valtonode(lookup("$record", symtab, 0), CFLD));
}
| FNCN '(' ')' { PUTS("func()");
$$ = op2(FNCN, $1, valtonode(lookup("$record", symtab, 0), CFLD));
}
| FNCN '(' expr ')' { PUTS("func(expr)"); $$ = op2(FNCN, $1, $3); }
| SPRINTF print_list { PUTS("sprintf"); $$ = op1($1, $2); }
| SUBSTR '(' expr ',' expr ',' expr ')'
{ PUTS("substr(e,e,e)"); $$ = op3(SUBSTR, $3, $5, $7); }
| SUBSTR '(' expr ',' expr ')'
{ PUTS("substr(e,e,e)"); $$ = op3(SUBSTR, $3, $5, nullstat); }
| SPLIT '(' expr ',' VAR ',' expr ')'
{ PUTS("split(e,e,e)"); $$ = op3(SPLIT, $3, $5, $7); }
| SPLIT '(' expr ',' VAR ')'
{ PUTS("split(e,e,e)"); $$ = op3(SPLIT, $3, $5, nullstat); }
| INDEX '(' expr ',' expr ')'
{ PUTS("index(e,e)"); $$ = op2(INDEX, $3, $5); }
| '(' expr ')' {PUTS("(expr)"); $$ = $2; }
| term '+' term { PUTS("t+t"); $$ = op2(ADD, $1, $3); }
| term '-' term { PUTS("t-t"); $$ = op2(MINUS, $1, $3); }
| term '*' term { PUTS("t*t"); $$ = op2(MULT, $1, $3); }
| term '/' term { PUTS("t/t"); $$ = op2(DIVIDE, $1, $3); }
| term '%' term { PUTS("t%t"); $$ = op2(MOD, $1, $3); }
| '-' term %prec QUEST { PUTS("-term"); $$ = op1(UMINUS, $2); }
| '+' term %prec QUEST { PUTS("+term"); $$ = $2; }
| INCR var { PUTS("++var"); $$ = op1(PREINCR, $2); }
| DECR var { PUTS("--var"); $$ = op1(PREDECR, $2); }
| var INCR { PUTS("var++"); $$= op1(POSTINCR, $1); }
| var DECR { PUTS("var--"); $$= op1(POSTDECR, $1); }
;
expr:
term { PUTS("term"); }
| expr term { PUTS("expr term"); $$ = op2(CAT, $1, $2); }
| var ASGNOP expr { PUTS("var=expr"); $$ = stat2($2, $1, $3); }
;
optNL:
NL
|
;
pa_stat:
pattern { PUTS("pattern"); $$ = stat2(PASTAT, $1, genprint()); }
| pattern '{' stat_list '}' { PUTS("pattern {...}"); $$ = stat2(PASTAT, $1, $3); }
| pattern ',' pattern { PUTS("srch,srch"); $$ = pa2stat($1, $3, genprint()); }
| pattern ',' pattern '{' stat_list '}'
{ PUTS("srch, srch {...}"); $$ = pa2stat($1, $3, $5); }
| '{' stat_list '}' { PUTS("null pattern {...}"); $$ = stat2(PASTAT, nullstat, $2); }
;
pa_stats:
pa_stats pa_stat st { PUTS("pa_stats pa_stat"); $$ = linkum($1, $2); }
| { PUTS("null pa_stat"); $$ = (hack)nullstat; }
| pa_stats pa_stat {PUTS("pa_stats pa_stat"); $$ = linkum($1, $2); }
;
pattern:
regular_expr { PUTS("regex");
$$ = op2(MATCH, valtonode(lookup("$record", symtab, 0), CFLD), makedfa($1));
}
| rel_expr { PUTS("relexpr"); }
| lex_expr { PUTS("lexexpr"); }
| compound_pattern { PUTS("comp pat"); }
;
print_list:
expr { PUTS("expr"); }
| pe_list { PUTS("pe_list"); }
| { PUTS("null print_list"); $$ = valtonode(lookup("$record", symtab, 0), CFLD); }
;
pe_list:
expr ',' expr {$$ = linkum($1, $3); }
| pe_list ',' expr {$$ = linkum($1, $3); }
| '(' pe_list ')' {$$ = $2; }
;
redir:
RELOP
| '|'
;
regular_expr:
'/' { startreg(); }
r '/'
{ PUTS("/r/"); $$ = $3; }
;
r:
CHAR { PUTS("regex CHAR"); $$ = op2(CHAR, (node *) 0, $1); }
| DOT { PUTS("regex DOT"); $$ = op2(DOT, (node *) 0, (node *) 0); }
| CCL { PUTS("regex CCL"); $$ = op2(CCL, (node *) 0, cclenter($1)); }
| NCCL { PUTS("regex NCCL"); $$ = op2(NCCL, (node *) 0, cclenter($1)); }
| '^' { PUTS("regex ^"); $$ = op2(CHAR, (node *) 0, HAT); }
| '$' { PUTS("regex $"); $$ = op2(CHAR, (node *) 0 ,(node *) 0); }
| r OR r { PUTS("regex OR"); $$ = op2(OR, $1, $3); }
| r r %prec CAT
{ PUTS("regex CAT"); $$ = op2(CAT, $1, $2); }
| r STAR { PUTS("regex STAR"); $$ = op2(STAR, $1, (node *) 0); }
| r PLUS { PUTS("regex PLUS"); $$ = op2(PLUS, $1, (node *) 0); }
| r QUEST { PUTS("regex QUEST"); $$ = op2(QUEST, $1, (node *) 0); }
| '(' r ')' { PUTS("(regex)"); $$ = $2; }
;
rel_expr:
expr RELOP expr
{ PUTS("expr relop expr"); $$ = op2($2, $1, $3); }
| '(' rel_expr ')'
{ PUTS("(relexpr)"); $$ = $2; }
;
st:
NL
| ';'
;
simple_stat:
PRINT print_list redir expr
{ PUTS("print>stat"); $$ = stat3($1, $2, $3, $4); }
| PRINT print_list
{ PUTS("print list"); $$ = stat3($1, $2, nullstat, nullstat); }
| PRINTF print_list redir expr
{ PUTS("printf>stat"); $$ = stat3($1, $2, $3, $4); }
| PRINTF print_list
{ PUTS("printf list"); $$ = stat3($1, $2, nullstat, nullstat); }
| expr { PUTS("expr"); $$ = exptostat($1); }
| { PUTS("null simple statement"); $$ = (hack)nullstat; }
| error { yyclearin; yyerror("illegal statement"); }
;
statement:
simple_stat st { PUTS("simple stat"); }
| if statement { PUTS("if stat"); $$ = stat3(IF, $1, $2, nullstat); }
| if statement else statement
{ PUTS("if-else stat"); $$ = stat3(IF, $1, $2, $4); }
| while statement { PUTS("while stat"); $$ = stat2(WHILE, $1, $2); }
| for { PUTS("for stat"); }
| NEXT st { PUTS("next"); $$ = stat1(NEXT, 0); }
| EXIT st { PUTS("exit"); $$ = stat1(EXIT, 0); }
| EXIT expr st { PUTS("exit"); $$ = stat1(EXIT, $2); }
| BREAK st { PUTS("break"); $$ = stat1(BREAK, 0); }
| CONTINUE st { PUTS("continue"); $$ = stat1(CONTINUE, 0); }
| '{' stat_list '}' { PUTS("{statlist}"); $$ = $2; }
;
stat_list:
stat_list statement { PUTS("stat_list stat"); $$ = linkum($1, $2); }
| { PUTS("null stat list"); $$ = (hack)nullstat; }
;
while:
WHILE '(' conditional ')' optNL { PUTS("while(cond)"); $$ = $3; }
;
for:
FOR '(' simple_stat ';' conditional ';' simple_stat ')' optNL statement
{ PUTS("for(e;e;e)"); $$ = stat4(FOR, $3, $5, $7, $10); }
| FOR '(' simple_stat ';' ';' simple_stat ')' optNL statement
{ PUTS("for(e;e;e)"); $$ = stat4(FOR, $3, nullstat, $6, $9); }
| FOR '(' VAR IN VAR ')' optNL statement
{ PUTS("for(v in v)"); $$ = stat3(IN, $3, $5, $8); }
;
%%
+169
View File
@@ -0,0 +1,169 @@
/* awk.lx.l 4.3 84/12/08 */
%Start A str chc sc reg comment
%{
#include "awk.h"
#include "awk.def.h"
#define YY_NO_INPUT /* defeat lex */
extern int yylval;
extern int mustfld;
int lineno = 1;
#define CADD cbuf[clen++]=yytext[0]; if(clen>=CBUFLEN-1) {yyerror("string too long", cbuf); BEGIN A;}
#define CBUFLEN 150
char cbuf[CBUFLEN];
int clen, cflag;
%}
A [a-zA-Z_]
B [a-zA-Z0-9_]
D [0-9]
WS [ \t]
%%
/* witchcraft */
/* switch (yybgin-yysvec-1) {
case 0:
BEGIN A;
break;
case sc:
BEGIN A;
return('}');
} */
<A>^\n lineno++;
<A>^{WS}*#.*\n lineno++; /* strip comment lines */
<A>{WS} ;
<A,reg>"\\"\n lineno++;
<A>"||" return(BOR);
<A>BEGIN return(XBEGIN);
<A>END return(XEND);
<A>PROGEND return(EOF);
<A>"&&" return(AND);
<A>"!" return(NOT);
<A>"!=" { yylval = NE; return(RELOP); }
<A>"~" { yylval = MATCH; return(MATCHOP); }
<A>"!~" { yylval = NOTMATCH; return(MATCHOP); }
<A>"<" { yylval = LT; return(RELOP); }
<A>"<=" { yylval = LE; return(RELOP); }
<A>"==" { yylval = EQ; return(RELOP); }
<A>">=" { yylval = GE; return(RELOP); }
<A>">" { yylval = GT; return(RELOP); }
<A>">>" { yylval = APPEND; return(RELOP); }
<A>"++" { yylval = INCR; return(INCR); }
<A>"--" { yylval = DECR; return(DECR); }
<A>"+=" { yylval = ADDEQ; return(ASGNOP); }
<A>"-=" { yylval = SUBEQ; return(ASGNOP); }
<A>"*=" { yylval = MULTEQ; return(ASGNOP); }
<A>"/=" { yylval = DIVEQ; return(ASGNOP); }
<A>"%=" { yylval = MODEQ; return(ASGNOP); }
<A>"=" { yylval = ASSIGN; return(ASGNOP); }
<A>"$"{D}+ { if (atoi(yytext+1)==0) {
yylval = (hack)lookup("$record", symtab, 0);
return(STRING);
} else {
yylval = fieldadr(atoi(yytext+1));
return(FIELD);
}
}
<A>"$"{WS}* { return(INDIRECT); }
<A>NF { mustfld=1; yylval = (hack)setsymtab(yytext, EMPTY, 0.0, NUM, symtab); return(VAR); }
<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)? {
yylval = (hack)setsymtab(yytext, EMPTY, atof(yytext), CON|NUM, symtab); return(NUMBER); }
<A>"}"{WS}*\n { BEGIN sc; lineno++; return(';'); }
<A>"}" { BEGIN sc; return(';'); }
<A>;\n { lineno++; return(';'); }
<A>\n { lineno++; return(NL); }
<A>while return(WHILE);
<A>for return(FOR);
<A>if return(IF);
<A>else return(ELSE);
<A>next return(NEXT);
<A>exit return(EXIT);
<A>break return(BREAK);
<A>continue return(CONTINUE);
<A>print { yylval = PRINT; return(PRINT); }
<A>printf { yylval = PRINTF; return(PRINTF); }
<A>sprintf { yylval = SPRINTF; return(SPRINTF); }
<A>split { yylval = SPLIT; return(SPLIT); }
<A>substr return(SUBSTR);
<A>index return(INDEX);
<A>in return(IN);
<A>getline return(GETLINE);
<A>length { yylval = FLENGTH; return(FNCN); }
<A>log { yylval = FLOG; return(FNCN); }
<A>int { yylval = FINT; return(FNCN); }
<A>exp { yylval = FEXP; return(FNCN); }
<A>sqrt { yylval = FSQRT; return(FNCN); }
<A>{A}{B}* { yylval = (hack)setsymtab(yytext, tostring(""), 0.0, STR|NUM, symtab); return(VAR); }
<A>\" { BEGIN str; clen=0; }
<A># { BEGIN comment; }
<comment>\n { BEGIN A; lineno++; return(NL); }
<comment>. ;
<A>. { yylval = yytext[0]; return(yytext[0]); }
<reg>"[" { BEGIN chc; clen=0; cflag=0; }
<reg>"[^" { BEGIN chc; clen=0; cflag=1; }
<reg>"?" return(QUEST);
<reg>"+" return(PLUS);
<reg>"*" return(STAR);
<reg>"|" return(OR);
<reg>"." return(DOT);
<reg>"(" return('(');
<reg>")" return(')');
<reg>"^" return('^');
<reg>"$" return('$');
<reg>\\{D}{D}{D} { sscanf(yytext+1, "%o", &yylval); return(CHAR); }
<reg>\\. { if (yytext[1]=='n') yylval = '\n';
else if (yytext[1] == 't') yylval = '\t';
else yylval = yytext[1];
return(CHAR);
}
<reg>"/" { BEGIN A; unput('/'); }
<reg>\n { yyerror("newline in regular expression"); lineno++; BEGIN A; }
<reg>. { yylval = yytext[0]; return(CHAR); }
<str>\" { char *s; BEGIN A; cbuf[clen]=0; s = tostring(cbuf);
cbuf[clen] = ' '; cbuf[++clen] = 0;
yylval = (hack)setsymtab(cbuf, s, 0.0, CON|STR, symtab); return(STRING); }
<str>\n { yyerror("newline in string"); lineno++; BEGIN A; }
<str>"\\\"" { cbuf[clen++]='"'; }
<str,chc>"\\"n { cbuf[clen++]='\n'; }
<str,chc>"\\"t { cbuf[clen++]='\t'; }
<str,chc>"\\\\" { cbuf[clen++]='\\'; }
<str>. { CADD; }
<chc>"\\""]" { cbuf[clen++]=']'; }
<chc>"]" { BEGIN reg; cbuf[clen]=0; yylval = (hack)tostring(cbuf);
if (cflag==0) { return(CCL); }
else { return(NCCL); } }
<chc>\n { yyerror("newline in character class"); lineno++; BEGIN A; }
<chc>. { CADD; }
%%
input()
{
register c;
extern char *lexprog;
if (yyin == NULL)
c = *lexprog++;
else
c = getc(yyin);
if (c == '\n')
yylineno++;
else if (c == EOF)
c = 0;
return(c);
}
startreg()
{
BEGIN reg;
}
+536
View File
@@ -0,0 +1,536 @@
#include <stdio.h>
#include <stdlib.h>
#include "awk.def.h"
#include "awk.h"
extern node *op2();
extern struct fa *cgotofn();
#define MAXLIN 256
#define NCHARS 128
#define NSTATES 256
#define type(v) v->nobj
#define left(v) v->narg[0]
#define right(v) v->narg[1]
#define parent(v) v->nnext
#define LEAF case CCL: case NCCL: case CHAR: case DOT:
#define UNARY case FINAL: case STAR: case PLUS: case QUEST:
/* encoding in tree nodes:
leaf (CCL, NCCL, CHAR, DOT): left is index, right contains value or pointer to value
unary (FINAL, STAR, PLUS, QUEST): left is child, right is null
binary (CAT, OR): left and right are children
parent contains pointer to parent
*/
struct fa {
int cch;
struct fa *st;
};
int *state[NSTATES];
int *foll[MAXLIN];
char chars[MAXLIN];
int setvec[MAXLIN];
node *point[MAXLIN];
int setcnt;
int line;
struct fa *makedfa(p) /* returns dfa for tree pointed to by p */
node *p;
{
node *p1;
struct fa *fap;
p1 = op2(CAT, op2(STAR, op2(DOT, (node *) 0, (node *) 0), (node *) 0), p);
/* put DOT STAR in front of reg. exp. */
p1 = op2(FINAL, p1, (node *) 0); /* install FINAL node */
line = 0;
penter(p1); /* enter parent pointers and leaf indices */
point[line] = p1; /* FINAL node */
setvec[0] = 1; /* for initial DOT STAR */
cfoll(p1); /* set up follow sets */
fap = cgotofn();
freetr(p1); /* add this when alloc works */
return(fap);
}
penter(p) /* set up parent pointers and leaf indices */
node *p;
{
switch(type(p)) {
LEAF
left(p) = (node *) line;
point[line++] = p;
break;
UNARY
penter(left(p));
parent(left(p)) = p;
break;
case CAT:
case OR:
penter(left(p));
penter(right(p));
parent(left(p)) = p;
parent(right(p)) = p;
break;
default:
error(FATAL, "unknown type %d in penter\n", type(p));
break;
}
}
freetr(p) /* free parse tree and follow sets */
node *p;
{
switch(type(p)) {
LEAF
xfree(foll[(int) left(p)]);
xfree(p);
break;
UNARY
freetr(left(p));
xfree(p);
break;
case CAT:
case OR:
freetr(left(p));
freetr(right(p));
xfree(p);
break;
default:
error(FATAL, "unknown type %d in freetr", type(p));
break;
}
}
char *cclenter(p)
register char *p;
{
register i, c;
char *op;
op = p;
i = 0;
while ((c = *p++) != 0) {
if (c == '-' && i > 0 && chars[i-1] != 0) {
if (*p != 0) {
c = chars[i-1];
while (c < *p) {
if (i >= MAXLIN)
overflo();
chars[i++] = ++c;
}
p++;
continue;
}
}
if (i >= MAXLIN)
overflo();
chars[i++] = c;
}
chars[i++] = '\0';
dprintf("cclenter: in = |%s|, out = |%s|\n", op, chars, NULL);
xfree(op);
return(tostring(chars));
}
overflo()
{
error(FATAL, "regular expression too long\n");
}
cfoll(v) /* enter follow set of each leaf of vertex v into foll[leaf] */
register node *v;
{
register i;
int prev;
int *add();
switch(type(v)) {
LEAF
setcnt = 0;
for (i=1; i<=line; i++)
setvec[i] = 0;
follow(v);
if (notin(foll, ( (int) left(v))-1, &prev)) {
foll[(int) left(v)] = add(setcnt);
}
else
foll[ (int) left(v)] = foll[prev];
break;
UNARY
cfoll(left(v));
break;
case CAT:
case OR:
cfoll(left(v));
cfoll(right(v));
break;
default:
error(FATAL, "unknown type %d in cfoll", type(v));
}
}
first(p) /* collects initially active leaves of p into setvec */
register node *p; /* returns 0 or 1 depending on whether p matches empty string */
{
register b;
switch(type(p)) {
LEAF
if (setvec[(int) left(p)] != 1) {
setvec[(int) left(p)] = 1;
setcnt++;
}
if (type(p) == CCL && (*(char *) right(p)) == '\0')
return(0); /* empty CCL */
else return(1);
case FINAL:
case PLUS:
if (first(left(p)) == 0) return(0);
return(1);
case STAR:
case QUEST:
first(left(p));
return(0);
case CAT:
if (first(left(p)) == 0 && first(right(p)) == 0) return(0);
return(1);
case OR:
b = first(right(p));
if (first(left(p)) == 0 || b == 0) return(0);
return(1);
}
error(FATAL, "unknown type %d in first\n", type(p));
return(-1);
}
follow(v)
node *v; /* collects leaves that can follow v into setvec */
{
node *p;
if (type(v) == FINAL)
return;
p = parent(v);
switch (type(p)) {
case STAR:
case PLUS: first(v);
follow(p);
return;
case OR:
case QUEST: follow(p);
return;
case CAT: if (v == left(p)) { /* v is left child of p */
if (first(right(p)) == 0) {
follow(p);
return;
}
}
else /* v is right child */
follow(p);
return;
case FINAL: if (setvec[line] != 1) {
setvec[line] = 1;
setcnt++;
}
return;
}
}
member(c, s) /* is c in s? */
register char c, *s;
{
while (*s)
if (c == *s++)
return(1);
return(0);
}
notin(array, n, prev) /* is setvec in array[0] thru array[n]? */
int **array;
int *prev; {
register i, j;
int *ptr;
for (i=0; i<=n; i++) {
ptr = array[i];
if (*ptr == setcnt) {
for (j=0; j < setcnt; j++)
if (setvec[*(++ptr)] != 1) goto nxt;
*prev = i;
return(0);
}
nxt: ;
}
return(1);
}
int *add(n) { /* remember setvec */
int *ptr, *p;
register i;
if ((p = ptr = (int *) malloc((n+1)*sizeof(int))) == NULL)
overflo();
*ptr = n;
dprintf("add(%d)\n", n, NULL, NULL);
for (i=1; i <= line; i++)
if (setvec[i] == 1) {
*(++ptr) = i;
dprintf(" ptr = %o, *ptr = %d, i = %d\n", ptr, *ptr, i);
}
dprintf("\n", NULL, NULL, NULL);
return(p);
}
struct fa *cgotofn()
{
register i, k;
register int *ptr;
char c;
char *p;
node *cp;
int j, n, s, ind, numtrans;
int finflg;
int curpos, num, prev;
struct fa *where[NSTATES];
int fatab[257];
struct fa *pfa;
char index[MAXLIN];
char iposns[MAXLIN];
int sposns[MAXLIN];
int spmax, spinit;
char symbol[NCHARS];
char isyms[NCHARS];
char ssyms[NCHARS];
int ssmax, ssinit;
for (i=0; i<=line; i++) index[i] = iposns[i] = setvec[i] = 0;
for (i=0; i<NCHARS; i++) isyms[i] = symbol[i] = 0;
setcnt = 0;
/* compute initial positions and symbols of state 0 */
ssmax = 0;
ptr = state[0] = foll[0];
spinit = *ptr;
for (i=0; i<spinit; i++) {
curpos = *(++ptr);
sposns[i] = curpos;
iposns[curpos] = 1;
cp = point[curpos];
dprintf("i = %d, spinit = %d, curpos = %d\n", i, spinit, curpos);
switch (type(cp)) {
case CHAR:
k = (int) right(cp);
if (isyms[k] != 1) {
isyms[k] = 1;
ssyms[ssmax++] = k;
}
break;
case DOT:
for (k=1; k<NCHARS; k++) {
if (k != HAT) {
if (isyms[k] != 1) {
isyms[k] = 1;
ssyms[ssmax++] = k;
}
}
}
break;
case CCL:
for (p = (char *) right(cp); *p; p++) {
if (*p != HAT) {
if (isyms[*p] != 1) {
isyms[*p] = 1;
ssyms[ssmax++] = *p;
}
}
}
break;
case NCCL:
for (k=1; k<NCHARS; k++) {
if (k != HAT && !member(k, (char *) right(cp))) {
if (isyms[k] != 1) {
isyms[k] = 1;
ssyms[ssmax++] = k;
}
}
}
}
}
ssinit = ssmax;
n = 0;
for (s=0; s<=n; s++) {
dprintf("s = %d\n", s, NULL, NULL);
ind = 0;
numtrans = 0;
finflg = 0;
if (*(state[s] + *state[s]) == line) { /* s final? */
finflg = 1;
goto tenter;
}
spmax = spinit;
ssmax = ssinit;
ptr = state[s];
num = *ptr;
for (i=0; i<num; i++) {
curpos = *(++ptr);
if (iposns[curpos] != 1 && index[curpos] != 1) {
index[curpos] = 1;
sposns[spmax++] = curpos;
}
cp = point[curpos];
switch (type(cp)) {
case CHAR:
k = (int) right(cp);
if (isyms[k] == 0 && symbol[k] == 0) {
symbol[k] = 1;
ssyms[ssmax++] = k;
}
break;
case DOT:
for (k=1; k<NCHARS; k++) {
if (k != HAT) {
if (isyms[k] == 0 && symbol[k] == 0) {
symbol[k] = 1;
ssyms[ssmax++] = k;
}
}
}
break;
case CCL:
for (p = (char *) right(cp); *p; p++) {
if (*p != HAT) {
if (isyms[*p] == 0 && symbol[*p] == 0) {
symbol[*p] = 1;
ssyms[ssmax++] = *p;
}
}
}
break;
case NCCL:
for (k=1; k<NCHARS; k++) {
if (k != HAT && !member(k, (char *) right(cp))) {
if (isyms[k] == 0 && symbol[k] == 0) {
symbol[k] = 1;
ssyms[ssmax++] = k;
}
}
}
}
}
for (j=0; j<ssmax; j++) { /* nextstate(s, ssyms[j]) */
c = ssyms[j];
symbol[c] = 0;
setcnt = 0;
for (k=0; k<=line; k++) setvec[k] = 0;
for (i=0; i<spmax; i++) {
index[sposns[i]] = 0;
cp = point[sposns[i]];
if ((k = type(cp)) != FINAL)
if (k == CHAR && c == (int) right(cp)
|| k == DOT
|| k == CCL && member(c, (char *) right(cp))
|| k == NCCL && !member(c, (char *) right(cp))) {
ptr = foll[sposns[i]];
num = *ptr;
for (k=0; k<num; k++) {
if (setvec[*(++ptr)] != 1
&& iposns[*ptr] != 1) {
setvec[*ptr] = 1;
setcnt++;
}
}
}
} /* end nextstate */
if (notin(state, n, &prev)) {
if (n >= NSTATES) {
dprintf("cgotofn: notin; state = %d, n = %d\n", state, n, NULL);
overflo();
}
state[++n] = add(setcnt);
dprintf(" delta(%d,%o) = %d", s,c,n);
dprintf(", ind = %d\n", ind+1, NULL, NULL);
fatab[++ind] = c;
fatab[++ind] = n;
numtrans++;
}
else {
if (prev != 0) {
dprintf(" delta(%d,%o) = %d", s,c,prev);
dprintf(", ind = %d\n", ind+1, NULL, NULL);
fatab[++ind] = c;
fatab[++ind] = prev;
numtrans++;
}
}
}
tenter:
if ((pfa = (struct fa *) malloc((numtrans + 1) * sizeof(struct fa))) == NULL)
overflo();
where[s] = pfa;
if (finflg)
pfa->cch = -1; /* s is a final state */
else
pfa->cch = numtrans;
pfa->st = 0;
for (i=1, pfa += 1; i<=numtrans; i++, pfa++) {
pfa->cch = fatab[2*i-1];
pfa->st = (struct fa *) fatab[2*i];
}
}
for (i=0; i<=n; i++) {
xfree(state[i]); /* free state[i] */
pfa = where[i];
pfa->st = where[0];
dprintf("state %d: (%o)\n", i, pfa, NULL);
dprintf(" numtrans = %d, default = %o\n", pfa->cch, pfa->st, NULL);
for (k=1; k<=pfa->cch; k++) {
(pfa+k)->st = where[ (int) (pfa+k)->st];
dprintf(" char = %o, nextstate = %o\n",(pfa+k)->cch, (pfa+k)->st, NULL);
}
}
pfa = where[0];
if ((num = pfa->cch) < 0)
return(where[0]);
for (pfa += num; num; num--, pfa--)
if (pfa->cch == HAT) {
return(pfa->st);
}
return(where[0]);
}
match(pfa, p)
register struct fa *pfa;
register char *p;
{
register count;
char c;
if (p == 0) return(0);
if (pfa->cch == 1) { /* fast test for first character, if possible */
c = (++pfa)->cch;
do
if (c == *p) {
p++;
pfa = pfa->st;
goto adv;
}
while (*p++ != 0);
return(0);
}
adv: if ((count = pfa->cch) < 0) return(1);
do {
for (pfa += count; count; count--, pfa--)
if (pfa->cch == *p) {
break;
}
pfa = pfa->st;
if ((count = pfa->cch) < 0) return(1);
} while(*p++ != 0);
return(0);
}
+39
View File
@@ -0,0 +1,39 @@
#include "stdio.h"
freeze(s)
char *s;
{
int fd;
unsigned int *len;
len = (unsigned int *)sbrk(0);
if((fd = creat(s, 0666)) < 0) {
perror(s);
return(1);
}
write(fd, &len, sizeof(len));
write(fd, (char *)0, len);
close(fd);
return(0);
}
thaw(s)
char *s;
{
int fd;
unsigned int *len;
if(*s == 0) {
fprintf(stderr, "empty restore file\n");
return(1);
}
if((fd = open(s, 0)) < 0) {
perror(s);
return(1);
}
read(fd, &len, sizeof(len));
(void) brk(len);
read(fd, (char *)0, len);
close(fd);
return(0);
}
+295
View File
@@ -0,0 +1,295 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include "awk.def.h"
#include "awk.h"
FILE *infile = NULL;
char *file;
#define RECSIZE (5 * 512)
char record[RECSIZE];
char fields[RECSIZE];
char EMPTY[] = "";
#define MAXFLD 100
int donefld; /* 1 = implies rec broken into fields */
int donerec; /* 1 = record is valid (no flds have changed) */
int mustfld; /* 1 = NF seen, so always break*/
#define FINIT {EMPTY, EMPTY, 0.0, FLD|STR}
cell fldtab[MAXFLD] = { /*room for fields */
{ "$record", record, 0.0, STR|FLD},
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT,
FINIT, FINIT, FINIT, FINIT, FINIT, FINIT, FINIT
};
int maxfld = 0; /* last used field */
void
error(int f, char *s, ...)
{
va_list ap;
va_start(ap, s);
fprintf(stderr, "awk: ");
vfprintf(stderr, s, ap);
fprintf(stderr, "\n");
va_end(ap);
if (NR && *NR > 0)
fprintf(stderr, " record number %g\n", *NR);
if (f)
exit(2);
}
getrec()
{
register char *rr;
extern int svargc;
extern char **svargv;
register c, sep;
dprintf("**RS=%o, **FS=%o\n", **RS, **FS, NULL);
donefld = 0;
donerec = 1;
record[0] = 0;
while (svargc > 0) {
dprintf("svargc=%d, *svargv=%s\n", svargc, *svargv, NULL);
if (infile == NULL) { /* have to open a new file */
if (member('=', *svargv)) { /* it's a var=value argument */
setclvar(*svargv);
svargv++;
svargc--;
continue;
}
*FILENAME = file = *svargv;
dprintf("opening file %s\n", file, NULL, NULL);
if (*file == '-')
infile = stdin;
else if ((infile = fopen(file, "r")) == NULL)
error(FATAL, "can't open %s", file);
}
if ((sep = **RS) == 0)
sep = '\n';
for (rr = record; ; ) {
for (; (c=getc(infile)) != sep && c != EOF; *rr++ = c)
;
if (**RS == sep || c == EOF)
break;
if ((c = getc(infile)) == '\n' || c == EOF) /* 2 in a row */
break;
*rr++ = '\n';
*rr++ = c;
}
if (rr > record+RECSIZE)
error(FATAL, "record `%.20s...' too long", record);
*rr = 0;
if (mustfld)
fldbld();
if (c != EOF || rr > record) { /* normal record */
recloc->tval &= ~NUM;
recloc->tval |= STR;
++nrloc->fval;
nrloc->tval &= ~STR;
nrloc->tval |= NUM;
return(1);
}
/* EOF arrived on this file; set up next */
if (infile != stdin)
fclose(infile);
infile = NULL;
svargc--;
svargv++;
}
return(0); /* true end of file */
}
setclvar(s) /* set var=value from s */
char *s;
{
char *p;
cell *q;
for (p=s; *p != '='; p++)
;
*p++ = 0;
q = setsymtab(s, tostring(p), 0.0, STR, symtab);
setsval(q, p);
dprintf("command line set %s to |%s|\n", s, p, NULL);
}
fldbld()
{
register char *r, *fr, sep;
int i, j;
r = record;
fr = fields;
i = 0; /* number of fields accumulated here */
if ((sep = **FS) == ' ')
for (i = 0; ; ) {
while (*r == ' ' || *r == '\t' || *r == '\n')
r++;
if (*r == 0)
break;
i++;
if (i >= MAXFLD)
error(FATAL, "record `%.20s...' has too many fields", record);
if (!(fldtab[i].tval&FLD))
strfree(fldtab[i].sval);
fldtab[i].sval = fr;
fldtab[i].tval = FLD | STR;
do
*fr++ = *r++;
while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
*fr++ = 0;
}
else if (*r != 0) /* if 0, it's a null field */
for (;;) {
i++;
if (i >= MAXFLD)
error(FATAL, "record `%.20s...' has too many fields", record);
if (!(fldtab[i].tval&FLD))
strfree(fldtab[i].sval);
fldtab[i].sval = fr;
fldtab[i].tval = FLD | STR;
while (*r != sep && *r != '\n' && *r != '\0') /* \n always a separator */
*fr++ = *r++;
*fr++ = 0;
if (*r++ == 0)
break;
}
*fr = 0;
for (j=MAXFLD-1; j>i; j--) { /* clean out junk from previous record */
if (!(fldtab[j].tval&FLD))
strfree(fldtab[j].sval);
fldtab[j].tval = STR | FLD;
fldtab[j].sval = EMPTY;
}
maxfld = i;
donefld = 1;
for(i=1; i<=maxfld; i++)
if(isnumber(fldtab[i].sval)) {
fldtab[i].fval = atof(fldtab[i].sval);
fldtab[i].tval |= NUM;
}
setfval(lookup("NF", symtab, 0), (awkfloat) maxfld);
if (dbg)
for (i = 0; i <= maxfld; i++)
printf("field %d: |%s|\n", i, fldtab[i].sval);
}
recbld()
{
int i;
register char *r, *p;
if (donefld == 0 || donerec == 1)
return;
r = record;
for (i = 1; i <= *NF; i++) {
p = getsval(&fldtab[i]);
while (*r++ = *p++)
;
*(r-1) = **OFS;
}
*(r-1) = '\0';
dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
recloc->tval = STR | FLD;
dprintf("in recbld FS=%o, recloc=%o\n", **FS, recloc, NULL);
if (r > record+RECSIZE)
error(FATAL, "built giant record `%.20s...'", record);
dprintf("recbld = |%s|\n", record, NULL, NULL);
}
cell *fieldadr(n)
{
if (n >= MAXFLD)
error(FATAL, "trying to access field %d", n);
return(&fldtab[n]);
}
int errorflag = 0;
yyerror(s)
char *s;
{
fprintf(stderr, "awk: %s near line %d\n", s, lineno);
errorflag = 2;
}
PUTS(s)
char *s;
{
dprintf("%s\n", s, NULL, NULL);
}
#define MAXEXPON 38 /* maximum exponenet for fp number */
isnumber(s)
register char *s;
{
register d1, d2;
int point;
char *es;
if (s == NULL)
return (0);
d1 = d2 = point = 0;
while (*s == ' ' || *s == '\t' || *s == '\n')
s++;
if (*s == '\0')
return(0); /* empty stuff isn't number */
if (*s == '+' || *s == '-')
s++;
if (!isdigit(*s) && *s != '.')
return(0);
if (isdigit(*s)) {
do {
d1++;
s++;
} while (isdigit(*s));
}
if(d1 >= MAXEXPON)
return(0); /* too many digits to convert */
if (*s == '.') {
point++;
s++;
}
if (isdigit(*s)) {
d2++;
do {
s++;
} while (isdigit(*s));
}
if (!(d1 || point && d2))
return(0);
if (*s == 'e' || *s == 'E') {
s++;
if (*s == '+' || *s == '-')
s++;
if (!isdigit(*s))
return(0);
es = s;
do {
s++;
} while (isdigit(*s));
if (s - es > 2)
return(0);
else if (s - es == 2 && 10 * (*es-'0') + *(es+1)-'0' >= MAXEXPON)
return(0);
}
while (*s == ' ' || *s == '\t' || *s == '\n')
s++;
if (*s == '\0')
return(1);
else
return(0);
}
/*
isnumber(s) char *s; {return(0);}
*/
+98
View File
@@ -0,0 +1,98 @@
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "awk.def.h"
#include "awk.h"
#define TOLOWER(c) (isupper(c) ? tolower(c) : c) /* ugh!!! */
int dbg = 0;
int svflg = 0;
int rstflg = 0;
int svargc;
char **svargv, **xargv;
extern FILE *yyin; /* lex input file */
char *lexprog; /* points to program argument if it exists */
extern errorflag; /* non-zero if any syntax errors; set by yyerror */
int filefd, symnum, ansfd;
char *filelist;
extern int maxsym, errno;
main(argc, argv)
int argc;
char *argv[];
{
if (argc == 1)
error(FATAL, "Usage: awk [-f source | 'cmds'] [files]");
syminit();
while (argc > 1) {
argc--;
argv++;
/* this nonsense is because gcos argument handling */
/* folds -F into -f. accordingly, one checks the next
/* character after f to see if it's -f file or -Fx.
*/
if (argv[0][0] == '-' && TOLOWER(argv[0][1]) == 'f' && argv[0][2] == '\0') {
yyin = fopen(argv[1], "r");
if (yyin == NULL)
error(FATAL, "can't open %s", argv[1]);
argc--;
argv++;
break;
} else if (argv[0][0] == '-' && TOLOWER(argv[0][1]) == 'f') { /* set field sep */
if (argv[0][2] == 't') /* special case for tab */
**FS = '\t';
else
**FS = argv[0][2];
continue;
} else if (argv[0][0] != '-') {
dprintf("cmds=|%s|\n", argv[0], NULL, NULL);
yyin = NULL;
lexprog = argv[0];
argv[0] = argv[-1]; /* need this space */
break;
} else if (strcmp("-d", argv[0])==0) {
dbg = 1;
}
else if(strcmp("-S", argv[0]) == 0) {
svflg = 1;
}
else if(strncmp("-R", argv[0], 2) == 0) {
if(thaw(argv[0] + 2) == 0)
rstflg = 1;
else {
fprintf(stderr, "not restored\n");
exit(1);
}
}
}
if (argc <= 1) {
argv[0][0] = '-';
argv[0][1] = '\0';
argc++;
argv--;
}
svargc = --argc;
svargv = ++argv;
dprintf("svargc=%d svargv[0]=%s\n", svargc, svargv[0], NULL);
*FILENAME = *svargv; /* initial file name */
if(rstflg == 0)
yyparse();
dprintf("errorflag=%d\n", errorflag, NULL, NULL);
if (errorflag)
exit(errorflag);
if(svflg) {
svflg = 0;
if(freeze("awk.out") != 0)
fprintf(stderr, "not saved\n");
exit(0);
}
run();
exit(errorflag);
}
yywrap()
{
return(1);
}
+148
View File
@@ -0,0 +1,148 @@
#include <stdio.h>
#include <stdlib.h>
#include "awk.def.h"
#include "awk.h"
node *ALLOC(n)
{
register node *x;
x = (node *) malloc(sizeof(node) + (n-1)*sizeof(node *));
if (x == NULL)
error(FATAL, "out of space in ALLOC");
return(x);
}
node *exptostat(a) node *a;
{
a->ntype = NSTAT;
return(a);
}
node *nullstat;
node *node0(a)
{
register node *x;
x=ALLOC(0);
x->nnext = NULL;
x->nobj=a;
return(x);
}
node *node1(a,b) node *b;
{
register node *x;
x=ALLOC(1);
x->nnext = NULL;
x->nobj=a;
x->narg[0]=b;
return(x);
}
node *node2(a,b,c) node *b, *c;
{
register node *x;
x = ALLOC(2);
x->nnext = NULL;
x->nobj = a;
x->narg[0] = b;
x->narg[1] = c;
return(x);
}
node *node3(a,b,c,d) node *b, *c, *d;
{
register node *x;
x = ALLOC(3);
x->nnext = NULL;
x->nobj = a;
x->narg[0] = b;
x->narg[1] = c;
x->narg[2] = d;
return(x);
}
node *node4(a,b,c,d,e) node *b, *c, *d, *e;
{
register node *x;
x = ALLOC(4);
x->nnext = NULL;
x->nobj = a;
x->narg[0] = b;
x->narg[1] = c;
x->narg[2] = d;
x->narg[3] = e;
return(x);
}
node *stat3(a,b,c,d) node *b, *c, *d;
{
register node *x;
x = node3(a,b,c,d);
x->ntype = NSTAT;
return(x);
}
node *op2(a,b,c) node *b, *c;
{
register node *x;
x = node2(a,b,c);
x->ntype = NEXPR;
return(x);
}
node *op1(a,b) node *b;
{
register node *x;
x = node1(a,b);
x->ntype = NEXPR;
return(x);
}
node *stat1(a,b) node *b;
{
register node *x;
x = node1(a,b);
x->ntype = NSTAT;
return(x);
}
node *op3(a,b,c,d) node *b, *c, *d;
{
register node *x;
x = node3(a,b,c,d);
x->ntype = NEXPR;
return(x);
}
node *stat2(a,b,c) node *b, *c;
{
register node *x;
x = node2(a,b,c);
x->ntype = NSTAT;
return(x);
}
node *stat4(a,b,c,d,e) node *b, *c, *d, *e;
{
register node *x;
x = node4(a,b,c,d,e);
x->ntype = NSTAT;
return(x);
}
node *valtonode(a, b) cell *a;
{
register node *x;
x = node0(a);
x->ntype = NVALUE;
x->subtype = b;
return(x);
}
node *pa2stat(a,b,c) node *a, *b, *c;
{
register node *x;
x = node3(paircnt++, a, b, c);
x->ntype = NPA2;
return(x);
}
node *linkum(a,b) node *a, *b;
{
register node *c;
if(a == NULL) return(b);
else if(b == NULL) return(a);
for(c=a; c->nnext != NULL; c=c->nnext);
c->nnext = b;
return(a);
}
node *genprint()
{
register node *x;
x = stat2(PRINT,valtonode(lookup("$record", symtab, 0), CFLD), nullstat);
return(x);
}
+99
View File
@@ -0,0 +1,99 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "awk.h"
struct tok
{ char *tnm;
int yval;
} tok[] = {
#include "token.h"
};
struct xx
{ int token;
char *name;
char *pname;
} proc[] = {
{ PROGRAM, "program", NULL},
{ BOR, "boolop", " || "},
{ AND, "boolop", " && "},
{ NOT, "boolop", " !"},
{ NE, "relop", " != "},
{ EQ, "relop", " == "},
{ LE, "relop", " <= "},
{ LT, "relop", " < "},
{ GE, "relop", " >= "},
{ GT, "relop", " > "},
{ ARRAY, "array", NULL},
{ INDIRECT, "indirect", "$("},
{ SUBSTR, "substr", "substr"},
{ INDEX, "sindex", "sindex"},
{ SPRINTF, "asprintf", "sprintf "},
{ ADD, "arith", " + "},
{ MINUS, "arith", " - "},
{ MULT, "arith", " * "},
{ DIVIDE, "arith", " / "},
{ MOD, "arith", " % "},
{ UMINUS, "arith", " -"},
{ PREINCR, "incrdecr", "++"},
{ POSTINCR, "incrdecr", "++"},
{ PREDECR, "incrdecr", "--"},
{ POSTDECR, "incrdecr", "--"},
{ CAT, "cat", " "},
{ PASTAT, "pastat", NULL},
{ PASTAT2, "dopa2", NULL},
{ MATCH, "matchop", " ~ "},
{ NOTMATCH, "matchop", " !~ "},
{ PRINTF, "aprintf", "printf"},
{ PRINT, "print", "print"},
{ SPLIT, "split", "split"},
{ ASSIGN, "assign", " = "},
{ ADDEQ, "assign", " += "},
{ SUBEQ, "assign", " -= "},
{ MULTEQ, "assign", " *= "},
{ DIVEQ, "assign", " /= "},
{ MODEQ, "assign", " %= "},
{ IF, "ifstat", "if("},
{ WHILE, "whilestat", "while("},
{ FOR, "forstat", "for("},
{ IN, "instat", "instat"},
{ NEXT, "jump", "next"},
{ EXIT, "jump", "exit"},
{ BREAK, "jump", "break"},
{ CONTINUE, "jump", "continue"},
{ FNCN, "fncn", "fncn"},
{ GETLINE, "getline", "getline"},
{ 0, ""},
};
#define SIZE LASTTOKEN - FIRSTTOKEN
char *table[SIZE];
char *names[SIZE];
char *tokname(n)
{
if (n<=256 || n >= LASTTOKEN)
n = 257;
return(tok[n-257].tnm);
}
int
main()
{ struct xx *p;
int i;
printf("#include \"awk.def.h\"\n");
printf("obj nullproc();\n");
for(p=proc;p->token!=0;p++)
if(p==proc || strcmp(p->name, (p-1)->name))
printf("extern obj %s();\n",p->name);
for(p=proc;p->token!=0;p++)
table[p->token-FIRSTTOKEN]=p->name;
printf("const objfunc proctab[%d] = {\n", SIZE);
for(i=0;i<SIZE;i++)
if(table[i]==0) printf("/*%s*/\tnullproc,\n",tokname(i+FIRSTTOKEN));
else printf("/*%s*/\t%s,\n",tokname(i+FIRSTTOKEN),table[i]);
printf("};\n");
exit(0);
}
+887
View File
@@ -0,0 +1,887 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "awk.def.h"
#include "awk.h"
#define RECSIZE BUFSIZ
#define FILENUM 10
#define PA2NUM 29
#define MAXTMP 20
struct
{
FILE *fp;
int type;
char *fname;
} files[FILENUM];
extern obj execute(), nodetoobj(), fieldel(), dopa2(), gettemp();
int pairstack[PA2NUM], paircnt;
node *winner = (node *)NULL;
cell tmps[MAXTMP];
static cell nullval = { EMPTY, EMPTY, 0.0, NUM, 0 };
obj true = { OBOOL, BTRUE, 0 };
obj false = { OBOOL, BFALSE, 0 };
run()
{
register int i;
execute(winner);
/* Wait for children to complete if output to a pipe. */
for (i=0; i<FILENUM; i++)
if (files[i].fp && files[i].type == '|')
pclose(files[i].fp);
}
obj execute(u) node *u;
{
register obj (*proc)();
obj x;
node *a;
if (u==(node *)NULL)
return(true);
for (a = u; ; a = a->nnext) {
if (cantexec(a))
return(nodetoobj(a));
if (a->ntype==NPA2)
proc=dopa2;
else {
if (notlegal(a->nobj))
error(FATAL, "illegal statement %o", a);
proc = proctab[a->nobj-FIRSTTOKEN];
}
x = (*proc)(a->narg,a->nobj);
if (isfld(x)) fldbld();
if (isexpr(a))
return(x);
/* a statement, goto next statement */
if (isjump(x))
return(x);
if (a->nnext == (node *)NULL)
return(x);
tempfree(x);
}
}
obj program(a, n) node **a;
{
obj x;
if (a[0] != NULL) {
x = execute(a[0]);
if (isexit(x))
return(true);
if (isjump(x))
error(FATAL, "unexpected break, continue or next");
tempfree(x);
}
while (getrec()) {
x = execute(a[1]);
if (isexit(x)) break;
tempfree(x);
}
tempfree(x);
if (a[2] != NULL) {
x = execute(a[2]);
if (isbreak(x) || isnext(x) || iscont(x))
error(FATAL, "unexpected break, continue or next");
tempfree(x);
}
return(true);
}
obj getline()
{
obj x;
x = gettemp();
setfval(x.optr, (awkfloat) getrec());
return(x);
}
obj array(a,n) node **a;
{
obj x, y;
extern obj arrayel();
x = execute(a[1]);
y = arrayel(a[0], x);
tempfree(x);
return(y);
}
obj arrayel(a,b) node *a; obj b;
{
char *s;
cell *x;
int i;
obj y;
s = getsval(b.optr);
x = (cell *) a;
if (!(x->tval&ARR)) {
strfree(x->sval);
x->tval &= ~STR;
x->tval |= ARR;
x->sval = (char *) makesymtab();
}
y.optr = setsymtab(s, tostring(""), 0.0, STR|NUM, x->sval);
y.otype = OCELL;
y.osub = CVAR;
return(y);
}
obj matchop(a,n) node **a;
{
obj x;
char *s;
int i;
x = execute(a[0]);
if (isstr(x)) s = x.optr->sval;
else s = getsval(x.optr);
tempfree(x);
i = match(a[1], s);
if (n==MATCH && i==1 || n==NOTMATCH && i==0)
return(true);
else
return(false);
}
obj boolop(a,n) node **a;
{
obj x, y;
int i;
x = execute(a[0]);
i = istrue(x);
tempfree(x);
switch (n) {
default:
error(FATAL, "unknown boolean operator %d", n);
case BOR:
if (i) return(true);
y = execute(a[1]);
i = istrue(y);
tempfree(y);
if (i) return(true);
else return(false);
case AND:
if ( !i ) return(false);
y = execute(a[1]);
i = istrue(y);
tempfree(y);
if (i) return(true);
else return(false);
case NOT:
if (i) return(false);
else return(true);
}
}
obj relop(a,n) node **a;
{
int i;
obj x, y;
awkfloat j;
x = execute(a[0]);
y = execute(a[1]);
if (x.optr->tval&NUM && y.optr->tval&NUM) {
j = x.optr->fval - y.optr->fval;
i = j<0? -1: (j>0? 1: 0);
} else {
i = strcmp(getsval(x.optr), getsval(y.optr));
}
tempfree(x);
tempfree(y);
switch (n) {
default:
error(FATAL, "unknown relational operator %d", n);
case LT: if (i<0) return(true);
else return(false);
case LE: if (i<=0) return(true);
else return(false);
case NE: if (i!=0) return(true);
else return(false);
case EQ: if (i==0) return(true);
else return(false);
case GE: if (i>=0) return(true);
else return(false);
case GT: if (i>0) return(true);
else return(false);
}
}
tempfree(a) obj a;
{
if (!istemp(a)) return;
strfree(a.optr->sval);
a.optr->tval = 0;
}
obj gettemp()
{
int i;
obj x;
for (i=0; i<MAXTMP; i++)
if (tmps[i].tval==0)
break;
if (i==MAXTMP)
error(FATAL, "out of temporaries in gettemp");
x.optr = &tmps[i];
tmps[i] = nullval;
x.otype = OCELL;
x.osub = CTEMP;
return(x);
}
obj indirect(a,n) node **a;
{
obj x;
int m;
cell *fieldadr();
x = execute(a[0]);
m = getfval(x.optr);
tempfree(x);
x.optr = fieldadr(m);
x.otype = OCELL;
x.osub = CFLD;
return(x);
}
obj substr(a, nnn) node **a;
{
char *s, temp;
obj x;
int k, m, n;
x = execute(a[0]);
s = getsval(x.optr);
k = strlen(s) + 1;
tempfree(x);
x = execute(a[1]);
m = getfval(x.optr);
if (m <= 0)
m = 1;
else if (m > k)
m = k;
tempfree(x);
if (a[2] != nullstat) {
x = execute(a[2]);
n = getfval(x.optr);
tempfree(x);
}
else
n = k - 1;
if (n < 0)
n = 0;
else if (n > k - m)
n = k - m;
dprintf("substr: m=%d, n=%d, s=%s\n", m, n, s);
x = gettemp();
temp = s[n+m-1]; /* with thanks to John Linderman */
s[n+m-1] = '\0';
setsval(x.optr, s + m - 1);
s[n+m-1] = temp;
return(x);
}
obj sindex(a, nnn) node **a;
{
obj x;
char *s1, *s2, *p1, *p2, *q;
x = execute(a[0]);
s1 = getsval(x.optr);
tempfree(x);
x = execute(a[1]);
s2 = getsval(x.optr);
tempfree(x);
x = gettemp();
for (p1 = s1; *p1 != '\0'; p1++) {
for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
;
if (*p2 == '\0') {
setfval(x.optr, (awkfloat) (p1 - s1 + 1)); /* origin 1 */
return(x);
}
}
setfval(x.optr, 0.0);
return(x);
}
char *format(s,a) char *s; node *a;
{
char *buf, *p, fmt[200], *t, *os;
obj x;
int flag = 0;
awkfloat xf;
os = s;
p = buf = (char *)malloc(RECSIZE);
while (*s) {
if (*s != '%') {
*p++ = *s++;
continue;
}
if (*(s+1) == '%') {
*p++ = '%';
s += 2;
continue;
}
for (t=fmt; (*t++ = *s) != '\0'; s++)
if (*s >= 'a' && *s <= 'z' && *s != 'l')
break;
*t = '\0';
if (t >= fmt + sizeof(fmt))
error(FATAL, "format item %.20s... too long", os);
switch (*s) {
case 'f': case 'e': case 'g':
flag = 1;
break;
case 'd':
flag = 2;
if(*(s-1) == 'l') break;
*(t-1) = 'l';
*t = 'd';
*++t = '\0';
break;
case 'o': case 'x':
flag = *(s-1)=='l' ? 2 : 3;
break;
case 'c':
flag = 3;
break;
case 's':
flag = 4;
break;
default:
flag = 0;
break;
}
if (flag == 0) {
sprintf(p, "%s", fmt);
p += strlen(p);
continue;
}
if (a == NULL)
error(FATAL, "not enough arguments in printf(%s)", os);
x = execute(a);
a = a->nnext;
if (flag != 4) /* watch out for converting to numbers! */
xf = getfval(x.optr);
if (flag==1) sprintf(p, fmt, xf);
else if (flag==2) sprintf(p, fmt, (long)xf);
else if (flag==3) sprintf(p, fmt, (int)xf);
else if (flag==4) sprintf(p, fmt, x.optr->sval==NULL ? "" : getsval(x.optr));
tempfree(x);
p += strlen(p);
s++;
}
*p = '\0';
return(buf);
}
obj asprintf(a,n) node **a;
{
obj x;
node *y;
char *s;
y = a[0]->nnext;
x = execute(a[0]);
s = format(getsval(x.optr), y);
tempfree(x);
x = gettemp();
x.optr->sval = s;
x.optr->tval = STR;
return(x);
}
obj arith(a,n) node **a;
{
awkfloat i,j;
obj x,y,z;
x = execute(a[0]);
i = getfval(x.optr);
tempfree(x);
if (n != UMINUS) {
y = execute(a[1]);
j = getfval(y.optr);
tempfree(y);
}
z = gettemp();
switch (n) {
default:
error(FATAL, "illegal arithmetic operator %d", n);
case ADD:
i += j;
break;
case MINUS:
i -= j;
break;
case MULT:
i *= j;
break;
case DIVIDE:
if (j == 0)
error(FATAL, "division by zero");
i /= j;
break;
case MOD:
if (j == 0)
error(FATAL, "division by zero");
i = i - j*(long)(i/j);
break;
case UMINUS:
i = -i;
break;
}
setfval(z.optr, i);
return(z);
}
obj incrdecr(a, n) node **a;
{
obj x, z;
int k;
awkfloat xf;
x = execute(a[0]);
xf = getfval(x.optr);
k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
if (n == PREINCR || n == PREDECR) {
setfval(x.optr, xf + k);
return(x);
}
z = gettemp();
setfval(z.optr, xf);
setfval(x.optr, xf + k);
tempfree(x);
return(z);
}
obj assign(a,n) node **a;
{
obj x, y;
awkfloat xf, yf;
x = execute(a[0]);
y = execute(a[1]);
if (n == ASSIGN) { /* ordinary assignment */
if ((y.optr->tval & (STR|NUM)) == (STR|NUM)) {
setsval(x.optr, y.optr->sval);
x.optr->fval = y.optr->fval;
x.optr->tval |= NUM;
}
else if (y.optr->tval & STR)
setsval(x.optr, y.optr->sval);
else if (y.optr->tval & NUM)
setfval(x.optr, y.optr->fval);
tempfree(y);
return(x);
}
xf = getfval(x.optr);
yf = getfval(y.optr);
switch (n) {
case ADDEQ:
xf += yf;
break;
case SUBEQ:
xf -= yf;
break;
case MULTEQ:
xf *= yf;
break;
case DIVEQ:
if (yf == 0)
error(FATAL, "division by zero");
xf /= yf;
break;
case MODEQ:
if (yf == 0)
error(FATAL, "division by zero");
xf = xf - yf*(long)(xf/yf);
break;
default:
error(FATAL, "illegal assignment operator %d", n);
break;
}
tempfree(y);
setfval(x.optr, xf);
return(x);
}
obj cat(a,q) node **a;
{
obj x,y,z;
int n1, n2;
char *s;
x = execute(a[0]);
y = execute(a[1]);
getsval(x.optr);
getsval(y.optr);
n1 = strlen(x.optr->sval);
n2 = strlen(y.optr->sval);
s = (char *) malloc(n1 + n2 + 1);
strcpy(s, x.optr->sval);
strcpy(s+n1, y.optr->sval);
tempfree(y);
z = gettemp();
z.optr->sval = s;
z.optr->tval = STR;
tempfree(x);
return(z);
}
obj pastat(a,n) node **a;
{
obj x;
if (a[0]==nullstat)
x = true;
else
x = execute(a[0]);
if (istrue(x)) {
tempfree(x);
x = execute(a[1]);
}
return(x);
}
obj dopa2(a,n) node **a;
{
obj x;
if (pairstack[n]==0) {
x = execute(a[0]);
if (istrue(x))
pairstack[n] = 1;
tempfree(x);
}
if (pairstack[n] == 1) {
x = execute(a[1]);
if (istrue(x))
pairstack[n] = 0;
tempfree(x);
x = execute(a[2]);
return(x);
}
return(false);
}
obj aprintf(a,n) node **a;
{
obj x;
x = asprintf(a,n);
if (a[1]==NULL) {
printf("%s", x.optr->sval);
tempfree(x);
return(true);
}
redirprint(x.optr->sval, (int)a[1], a[2]);
return(x);
}
obj split(a,nnn) node **a;
{
obj x;
cell *ap;
register char *s, *p;
char *t, temp, num[5];
register int sep;
int n, flag;
x = execute(a[0]);
s = getsval(x.optr);
tempfree(x);
if (a[2] == nullstat)
sep = **FS;
else {
x = execute(a[2]);
sep = getsval(x.optr)[0];
tempfree(x);
}
ap = (cell *) a[1];
freesymtab(ap);
dprintf("split: s=|%s|, a=%s, sep=|%c|\n", s, ap->nval, sep);
ap->tval &= ~STR;
ap->tval |= ARR;
ap->sval = (char *) makesymtab();
n = 0;
if (sep == ' ')
for (n = 0; ; ) {
while (*s == ' ' || *s == '\t' || *s == '\n')
s++;
if (*s == 0)
break;
n++;
t = s;
do
s++;
while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
temp = *s;
*s = '\0';
sprintf(num, "%d", n);
if (isnumber(t))
setsymtab(num, tostring(t), atof(t), STR|NUM, ap->sval);
else
setsymtab(num, tostring(t), 0.0, STR, ap->sval);
*s = temp;
if (*s != 0)
s++;
}
else if (*s != 0)
for (;;) {
n++;
t = s;
while (*s != sep && *s != '\n' && *s != '\0')
s++;
temp = *s;
*s = '\0';
sprintf(num, "%d", n);
if (isnumber(t))
setsymtab(num, tostring(t), atof(t), STR|NUM, ap->sval);
else
setsymtab(num, tostring(t), 0.0, STR, ap->sval);
*s = temp;
if (*s++ == 0)
break;
}
x = gettemp();
x.optr->tval = NUM;
x.optr->fval = n;
return(x);
}
obj ifstat(a,n) node **a;
{
obj x;
x = execute(a[0]);
if (istrue(x)) {
tempfree(x);
x = execute(a[1]);
}
else if (a[2] != nullstat) {
tempfree(x);
x = execute(a[2]);
}
return(x);
}
obj whilestat(a,n) node **a;
{
obj x;
for (;;) {
x = execute(a[0]);
if (!istrue(x)) return(x);
tempfree(x);
x = execute(a[1]);
if (isbreak(x)) {
x = true;
return(x);
}
if (isnext(x) || isexit(x))
return(x);
tempfree(x);
}
}
obj forstat(a,n) node **a;
{
obj x;
tempfree(execute(a[0]));
for (;;) {
if (a[1]!=nullstat) {
x = execute(a[1]);
if (!istrue(x)) return(x);
else tempfree(x);
}
x = execute(a[3]);
if (isbreak(x)) { /* turn off break */
x = true;
return(x);
}
if (isnext(x) || isexit(x))
return(x);
tempfree(x);
tempfree(execute(a[2]));
}
}
obj instat(a, n) node **a;
{
cell *vp, *arrayp, *cp, **tp;
obj x;
int i;
vp = (cell *) a[0];
arrayp = (cell *) a[1];
if (!(arrayp->tval & ARR))
error(FATAL, "%s is not an array", arrayp->nval);
tp = (cell **) arrayp->sval;
for (i = 0; i < MAXSYM; i++) { /* this routine knows too much */
for (cp = tp[i]; cp != NULL; cp = cp->nextval) {
setsval(vp, cp->nval);
x = execute(a[2]);
if (isbreak(x)) {
x = true;
return(x);
}
if (isnext(x) || isexit(x))
return(x);
tempfree(x);
}
}
return (true);
}
obj jump(a,n) node **a;
{
obj x, y;
x.otype = OJUMP;
switch (n) {
default:
error(FATAL, "illegal jump type %d", n);
break;
case EXIT:
if (a[0] != 0) {
y = execute(a[0]);
errorflag = getfval(y.optr);
}
x.osub = JEXIT;
break;
case NEXT:
x.osub = JNEXT;
break;
case BREAK:
x.osub = JBREAK;
break;
case CONTINUE:
x.osub = JCONT;
break;
}
return(x);
}
obj fncn(a,n) node **a;
{
obj x;
awkfloat u;
int t;
t = (int) a[0];
x = execute(a[1]);
if (t == FLENGTH)
u = (awkfloat) strlen(getsval(x.optr));
else if (t == FLOG)
u = log(getfval(x.optr));
else if (t == FINT)
u = (awkfloat) (long) getfval(x.optr);
else if (t == FEXP)
u = exp(getfval(x.optr));
else if (t == FSQRT)
u = sqrt(getfval(x.optr));
else
error(FATAL, "illegal function type %d", t);
tempfree(x);
x = gettemp();
setfval(x.optr, u);
return(x);
}
obj print(a,n) node **a;
{
register node *x;
obj y;
char s[RECSIZE];
s[0] = '\0';
for (x=a[0]; x!=NULL; x=x->nnext) {
y = execute(x);
strcat(s, getsval(y.optr));
tempfree(y);
if (x->nnext==NULL)
strcat(s, *ORS);
else
strcat(s, *OFS);
}
if (strlen(s) >= RECSIZE)
error(FATAL, "string %.20s ... too long to print", s);
if (a[1]==nullstat) {
printf("%s", s);
return(true);
}
redirprint(s, (int)a[1], a[2]);
return(false);
}
obj nullproc() {}
obj nodetoobj(a) node *a;
{
obj x;
x.optr = (cell *) a->nobj;
x.otype = OCELL;
x.osub = a->subtype;
if (isfld(x)) fldbld();
return(x);
}
redirprint(s, a, b) char *s; node *b;
{
register int i;
obj x;
x = execute(b);
getsval(x.optr);
for (i=0; i<FILENUM; i++)
if (files[i].fp && strcmp(x.optr->sval, files[i].fname) == 0)
goto doit;
for (i=0; i<FILENUM; i++)
if (files[i].fp == 0)
break;
if (i >= FILENUM)
error(FATAL, "too many output files %d", i);
if (a == '|') /* a pipe! */
files[i].fp = popen(x.optr->sval, "w");
else if (a == APPEND)
files[i].fp = fopen(x.optr->sval, "a");
else
files[i].fp = fopen(x.optr->sval, "w");
if (files[i].fp == NULL)
error(FATAL, "can't open file %s", x.optr->sval);
files[i].fname = tostring(x.optr->sval);
files[i].type = a;
doit:
fprintf(files[i].fp, "%s", s);
#ifndef gcos
fflush(files[i].fp); /* in case someone is waiting for the output */
#endif
tempfree(x);
}
+8
View File
@@ -0,0 +1,8 @@
e y.tab.h
1,$g!/#define /d
1,$s/# *define *//
1,$s/^/{"/
1,$s/ /", /
1,$s/$/},/
w! token.h
q
+252
View File
@@ -0,0 +1,252 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "awk.def.h"
#include "awk.h"
cell *symtab[MAXSYM]; /* symbol table pointers */
char **FS; /* initial field sep */
char **RS; /* initial record sep */
char **OFS; /* output field sep */
char **ORS; /* output record sep */
char **OFMT; /*output format for numbers*/
awkfloat *NF; /* number of fields in current record */
awkfloat *NR; /* number of current record */
char **FILENAME; /* current filename argument */
cell *recloc; /* location of record */
cell *nrloc; /* NR */
cell *nfloc; /* NF */
syminit()
{
setsymtab("0", tostring("0"), 0.0, NUM|STR|CON|FLD, symtab);
/* this one is used for if(x)... tests: */
setsymtab("$zero&null", tostring(""), 0.0, NUM|STR|CON|FLD, symtab);
recloc = setsymtab("$record", record, 0.0, STR|FLD, symtab);
dprintf("recloc %o lookup %o\n", recloc, lookup("$record", symtab, 0), NULL);
FS = &setsymtab("FS", tostring(" "), 0.0, STR|FLD, symtab)->sval;
RS = &setsymtab("RS", tostring("\n"), 0.0, STR|FLD, symtab)->sval;
OFS = &setsymtab("OFS", tostring(" "), 0.0, STR|FLD, symtab)->sval;
ORS = &setsymtab("ORS", tostring("\n"), 0.0, STR|FLD, symtab)->sval;
OFMT = &setsymtab("OFMT", tostring("%.6g"), 0.0, STR|FLD, symtab)->sval;
FILENAME = &setsymtab("FILENAME", EMPTY, 0.0, STR|FLD, symtab)->sval;
nfloc = setsymtab("NF", EMPTY, 0.0, NUM, symtab);
NF = &nfloc->fval;
nrloc = setsymtab("NR", EMPTY, 0.0, NUM, symtab);
NR = &nrloc->fval;
}
cell **makesymtab()
{
int i;
cell **cp;
cp = (cell **) malloc(MAXSYM * sizeof(cell *));
if (cp == NULL)
error(FATAL, "out of space in makesymtab");
for (i = 0; i < MAXSYM; i++)
cp[i] = 0;
return(cp);
}
freesymtab(ap) /* free symbol table */
cell *ap;
{
cell *cp, **tp;
int i;
if (!(ap->tval & ARR))
return;
tp = (cell **) ap->sval;
for (i = 0; i < MAXSYM; i++) {
for (cp = tp[i]; cp != NULL; cp = cp->nextval) {
strfree(cp->nval);
strfree(cp->sval);
free(cp);
}
}
xfree(tp);
}
cell *setsymtab(n, s, f, t, tab)
char *n, *s;
awkfloat f;
unsigned t;
cell **tab;
{
register h;
register cell *p;
cell *lookup();
if (n != NULL && (p = lookup(n, tab, 0)) != NULL) {
if (s != EMPTY ) xfree(s); /* careful here */
dprintf("setsymtab found %o: %s", p, p->nval, NULL);
dprintf(" %s %g %o\n", p->sval, p->fval, p->tval);
return(p);
}
p = (cell *) malloc(sizeof(cell));
if (p == NULL)
error(FATAL, "symbol table overflow at %s", n);
p->nval = tostring(n);
p->sval = s;
p->fval = f;
p->tval = t;
h = hash(n);
p->nextval = tab[h];
tab[h] = p;
dprintf("setsymtab set %o: %s", p, p->nval, NULL);
dprintf(" %s %g %o\n", p->sval, p->fval, p->tval);
return(p);
}
hash(s) /* form hash value for string s */
register unsigned char *s;
{
register int hashval;
for (hashval = 0; *s != '\0'; )
hashval += *s++;
return(hashval % MAXSYM);
}
cell *lookup(s, tab, flag) /* look for s in tab, flag must match*/
register char *s;
cell **tab;
{
register cell *p;
for (p = tab[hash(s)]; p != NULL; p = p->nextval)
if (strcmp(s, p->nval) == 0 &&
(flag == 0 || flag == p->tval))
return(p); /* found it */
return(NULL); /* not found */
}
awkfloat setfval(vp, f)
register cell *vp;
awkfloat f;
{
dprintf("setfval: %o %g\n", vp, f, NULL);
checkval(vp);
if (vp == recloc)
error(FATAL, "can't set $0");
vp->tval &= ~STR; /* mark string invalid */
vp->tval |= NUM; /* mark number ok */
if ((vp->tval & FLD) && isnull(vp->nval))
donerec = 0;
return(vp->fval = f);
}
char *setsval(vp, s)
register cell *vp;
char *s;
{
dprintf("setsval: %o %s\n", vp, s, NULL);
checkval(vp);
if (vp == recloc)
error(FATAL, "can't set $0");
vp->tval &= ~NUM;
vp->tval |= STR;
if ((vp->tval & FLD) && isnull(vp->nval))
donerec = 0;
if (!(vp->tval&FLD))
strfree(vp->sval);
vp->tval &= ~FLD;
return(vp->sval = tostring(s));
}
awkfloat getfval(vp)
register cell *vp;
{
if (vp->sval == record && donerec == 0)
recbld();
dprintf("getfval: %o", vp, NULL, NULL);
checkval(vp);
if ((vp->tval & NUM) == 0) {
/* the problem is to make non-numeric things */
/* have unlikely numeric variables, so that */
/* $1 == $2 comparisons sort of make sense when */
/* one or the other is numeric */
if (isnumber(vp->sval)) {
vp->fval = atof(vp->sval);
if (!(vp->tval & CON)) /* don't change type of a constant */
vp->tval |= NUM;
}
else
vp->fval = 0.0; /* not a very good idea */
}
dprintf(" %g\n", vp->fval, NULL, NULL);
return(vp->fval);
}
char *getsval(vp)
register cell *vp;
{
char s[100];
if (vp->sval == record && donerec == 0)
recbld();
dprintf("getsval: %o", vp, NULL, NULL);
checkval(vp);
if ((vp->tval & STR) == 0) {
if (!(vp->tval&FLD))
strfree(vp->sval);
if ((long)vp->fval==vp->fval)
sprintf(s, "%.20g", vp->fval);
else
sprintf(s, *OFMT, vp->fval);
vp->sval = tostring(s);
vp->tval &= ~FLD;
vp->tval |= STR;
}
dprintf(" %s\n", vp->sval, NULL, NULL);
return(vp->sval);
}
checkval(vp)
register cell *vp;
{
if (vp->tval & ARR)
error(FATAL, "illegal reference to array %s", vp->nval);
if ((vp->tval & (NUM | STR)) == 0)
error(FATAL, "funny variable %o: %s %s %g %o", vp, vp->nval,
vp->sval, vp->fval, vp->tval);
}
char *tostring(s)
register char *s;
{
register char *p;
if (s==NULL){
p = malloc(1);
if (p == NULL)
error(FATAL, "out of space in tostring on %s", s);
*p = '\0';
} else {
p = malloc(strlen(s)+1);
if (p == NULL)
error(FATAL, "out of space in tostring on %s", s);
strcpy(p, s);
}
return(p);
}
#ifndef yfree
yfree(a) char *a;
{
printf("%o\n", a);
free(a);
}
#endif
#ifdef malloc
#undef malloc
char *ymalloc(u) unsigned u;
{ char *p;
p = malloc(u);
printf("%o %o\n", u, p);
return(p);
}
#endif
+30
View File
@@ -0,0 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
main(argc, argv)
char **argv;
{
register char *p1, *p2, *p3;
if (argc < 2) {
putchar('\n');
exit(1);
}
p1 = argv[1];
p2 = p1;
while (*p1) {
if (*p1++ == '/')
p2 = p1;
}
if (argc>2) {
for(p3=argv[2]; *p3; p3++)
;
while(p1>p2 && p3>argv[2])
if(*--p3 != *--p1)
goto output;
*p1 = '\0';
}
output:
puts(p2);
exit(0);
}
+30
View File
@@ -0,0 +1,30 @@
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
CFLAGS += -Wall -Werror
OBJS = basic.o
LIBS = -lcurses -ltermcap -lm -lc
all: basic renumber
basic: ${OBJS}
${CC} ${LDFLAGS} -o basic.elf ${OBJS} ${LIBS}
${OBJDUMP} -S basic.elf > basic.dis
${SIZE} basic.elf
${ELF2AOUT} basic.elf $@ && rm basic.elf
renumber: renumber.o
${CC} ${LDFLAGS} -o renumber.elf $< ${LIBS}
${OBJDUMP} -S renumber.elf > renumber.dis
${SIZE} renumber.elf
${ELF2AOUT} renumber.elf $@ && rm renumber.elf
clean:
rm -f *.o basic renumber *.elf *.dis *~
install: all
install basic $(DESTDIR)/bin/
install renumber $(DESTDIR)/bin/
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
10 rem **************************************
20 rem *** Play the "blackjack" (21) game ***
30 rem **************************************
40 dim C(52): m = 1000
50 rem
60 rem Create deck of cards and shuffle it
70 rem
80 for i=0 to 51: c(i) = i: next i
90 for i=0 to 51: i1=rnd(52): i2=c(i): c(i)=c(i2): c(i2)=i1: next i
100 rem
110 rem Prompt for amount of bet (on this game)
120 rem
130 print "You have", m, " dollars"
140 input "How much do you wish to bet?", b: if b=0 then stop
150 lif b>m then print "You don't have enough money":goto 140
160 t = 0: d = 0
170 rem
180 rem Prompt PLAYER for another card
190 rem
200 print "Total:", t,:Input " Another card (Y/N)?", a$
210 if a$="n" then 380
220 lif a$<>"y" then print "Please answer y-Yes or n-No":goto 200
230 c = c(d): d = d + 1: gosub 530
240 c = c % 13: if c > 9 then c = 9
250 if c > 0 then 300
260 input "(1)one or (t)ten ?", a$
270 if a$="1" then 300
280 if a$<>"t" then 260
290 c = 9
300 t = t + c + 1
310 if t <= 21 then 200
320 print "You went over 21! - you LOSE!"
330 m = m - b: if m > 0 then 80
340 print "You went BUST!":end
350 rem
360 rem Play DEALER
370 rem
380 t1 = 0
390 c = c(d): d = d + 1: print "Dealer draws ",: gosub 530
400 c = c % 13: if c > 9 then c = 9
410 if c > 0 then 470
420 if t1 < 10 then 450
430 if (t1+10) > 23 then 460
440 if (t1+10) >= t then 450
450 c = 9
460 print "Dealer chooses", c+1
470 t1 = t1 + c + 1: print "Dealer totals", t1: if t1 < t then 390
480 lif t1 <= 21 then print "Dealer wins - You LOSE!": goto 330
490 print "Dealer loses - You WIN!!!": m = m + b: goto 80
500 rem
510 rem Subroutine to display text description of a card
520 rem
530 order 590
540 for a = 0 to c / 13: read a$: next a
550 order 600
560 for a = 0 to c % 13: read a1$:next a
570 print a1$, " of ", a$
580 return
590 data "Hearts", "Diamonds", "Clubs", "Spades"
600 data "Ace", "Two", "Three", "Four", "Five", "Six", "Seven"
610 data "Eight", "Nine", "Ten", "Jack", "Queen", "King"
+13
View File
@@ -0,0 +1,13 @@
10 rem ****************************
20 rem *** Play the HI/LOW game ***
30 rem ****************************
40 n = rnd(100)
50 c = 0
60 input "Guess a number? ", g
70 c = c+1
80 if g=n then 120
90 if g>n then print "lower"
100 if g<n then print "higher"
110 goto 60
120 print "You guessed it in", c, " tries!"
130 exit
+20
View File
@@ -0,0 +1,20 @@
This is a version of Basic adapted for RetroBSD.
It is based on Micro-Basic from Dave Dunfield:
* Copyright 1982-2000 Dave Dunfield
* All rights reserved.
* Permission granted for personal (non-commercial) use only.
How to build:
- From command prompt type: "make"
Archive contents:
- BASIC.C = original Mikro-C source code
- README.TXT = this file
- BLKJACK.BAS = example does work
- HILOW.BAS = example works ok
- Makefile = Makefile
- RENUMBER.C = RENUMBER source code
___
Best wishes,
Serge Vakulenko <serge@vak.ru>
+122
View File
@@ -0,0 +1,122 @@
/*
* MICRO-BASIC 2.1 line renumbering program.
*
* This program reads a MICRO-BASIC source file, and write a new one with
* all lines renumbered. All IF/THEN, GOTO, GOSUB and ORDER statements are
* adjusted to reflect the new line numbers.
*
* Copyright 1993-2000 Dave Dunfield
* All rights reserved.
*
* Permission granted for personal (non-commercial) use only.
*
* Compile command: cc renumber -fop
*/
#ifdef CROSS
# include </usr/include/stdio.h>
# include </usr/include/ctype.h>
#else
# include <stdio.h>
# include <ctype.h>
#endif
#include <stdlib.h>
#define MAX_LINES 10000 /* Maximum # lines in input program */
/*
* Case insensitive test of 'ptr' beginning with 'string'
*/
int begins_with(char *ptr, char *string)
{
while(*string)
if(toupper(*ptr++) != *string++)
return 0;
return -1;
}
int main(int argc, char *argv[])
{
unsigned i, l, m;
char buffer[200], *ptr, *ptr1;
static unsigned lines[MAX_LINES], ltop = 0, increment = 10, start = 10;
static FILE *fp, *fp1;
printf("MICRO-BASIC 2.1 line renumbering program\n");
if (argc < 3) {
fprintf(stderr, "Use: renumber old new [start [increment]]\n\n");
fprintf(stderr, "Copyright 1993-2000 Dave Dunfield\n");
fprintf(stderr, "All rights reserved.\n");
return 1;
}
fp = fopen(argv[1], "rvq");
fp1 = fopen(argv[2], "wvq");
if(argc > 3)
start = atoi(argv[3]);
if(argc > 4)
increment = atoi(argv[4]);
/* Pass #1: Scan and record all line numbers */
m = 0;
while(fgets(buffer, sizeof(buffer)-1, fp)) {
if(!(l = atoi(buffer))) {
printf("Invalid line number following line %u\n", m);
return 0;
}
if(l <= m) {
printf("Improper line sequence following line %u\n", m);
return 0;
}
lines[ltop++] = m = l;
}
/* Pass #2: Copy lines and replace line numbers */
rewind(fp);
m = 0;
while(fgets(ptr1 = ptr = buffer, sizeof(buffer), fp)) {
/* Replace line number with one from the new sequence */
fixnum: while(isspace(*ptr))
++ptr;
while(ptr1 < ptr)
putc(*ptr1++, fp1);
if(isdigit(*ptr)) {
++m;
l = atoi(ptr);
while(isdigit(*ptr))
++ptr;
for(i=0; i < ltop; ++i)
if(lines[i] == l) {
fprintf(fp1, "%u", i * increment + start);
break;
}
}
while(*(ptr1 = ptr)) {
if(begins_with(ptr, "THEN")) {
ptr += 4;
goto fixnum;
}
if(begins_with(ptr, "ORDER")) {
ptr += 5;
goto fixnum;
}
if(begins_with(ptr, "GOTO")) {
ptr += 4;
goto fixnum;
}
if(begins_with(ptr, "GOSUB")) {
ptr += 5;
goto fixnum;
}
if (*ptr != '\r' && *ptr != '\n')
putc(*ptr, fp1);
++ptr;
}
putc('\n', fp1);
}
fclose(fp1);
fclose(fp);
printf("%u lines read, %u fixups\n", ltop, m);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
10 INPUT "Your name: ", U$
20 PRINT "Hello ", U$
30 INPUT "How many stars do you want: ", N
40 S$ = ""
50 FOR I = 1 TO N
60 S$ = S$ + "*"
70 NEXT I
80 PRINT S$
90 INPUT "Do you want more stars? ", A$
100 IF A$ = "" THEN GOTO 90
110 IF A$ = "Y" THEN GOTO 30
120 IF A$ = "y" THEN GOTO 30
130 PRINT "Goodbye ", U$
140 END
+613
View File
@@ -0,0 +1,613 @@
%{
int *getout();
%}
%right '='
%left '+' '-'
%left '*' '/' '%'
%right '^'
%left UMINUS
%term LETTER DIGIT SQRT LENGTH _IF FFF EQ
%term _WHILE _FOR NE LE GE INCR DECR
%term _RETURN _BREAK _DEFINE BASE OBASE SCALE
%term EQPL EQMI EQMUL EQDIV EQREM EQEXP
%term _AUTO DOT
%term QSTR
%{
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
FILE *in;
char cary[1000], *cp = { cary };
char string[1000], *str = {string};
int crs = '0';
int rcrs = '0'; /* reset crs */
int bindx = 0;
int lev = 0;
int ln;
char *ss;
int bstack[10] = { 0 };
char *numb[15] = {
" 0", " 1", " 2", " 3", " 4", " 5",
" 6", " 7", " 8", " 9", " 10", " 11",
" 12", " 13", " 14" };
int *pre, *post;
%}
%%
start :
| start stat tail
= output( $2 );
| start def dargs ')' '{' dlist slist '}'
={ bundle( 6,pre, $7, post ,"0",numb[lev],"Q");
conout( $$, $2 );
rcrs = crs;
output( "" );
lev = bindx = 0;
}
;
dlist : tail
| dlist _AUTO dlets tail
;
stat : e
={ bundle(2, $1, "ps." ); }
|
={ bundle(1, "" ); }
| QSTR
={ bundle(3,"[",$1,"]P");}
| LETTER '=' e
={ bundle(3, $3, "s", $1 ); }
| LETTER '[' e ']' '=' e
={ bundle(4, $6, $3, ":", geta($1)); }
| LETTER EQOP e
={ bundle(6, "l", $1, $3, $2, "s", $1 ); }
| LETTER '[' e ']' EQOP e
={ bundle(8,$3, ";", geta($1), $6, $5, $3, ":", geta($1));}
| _BREAK
={ bundle(2, numb[lev-bstack[bindx-1]], "Q" ); }
| _RETURN '(' e ')'
= bundle(4, $3, post, numb[lev], "Q" );
| _RETURN '(' ')'
= bundle(4, "0", post, numb[lev], "Q" );
| _RETURN
= bundle(4,"0",post,numb[lev],"Q");
| SCALE '=' e
= bundle(2, $3, "k");
| SCALE EQOP e
= bundle(4,"K",$3,$2,"k");
| BASE '=' e
= bundle(2,$3, "i");
| BASE EQOP e
= bundle(4,"I",$3,$2,"i");
| OBASE '=' e
= bundle(2,$3,"o");
| OBASE EQOP e
= bundle(4,"O",$3,$2,"o");
| '{' slist '}'
={ $$ = $2; }
| FFF
={ bundle(1,"fY"); }
| error
={ bundle(1,"c"); }
| _IF CRS BLEV '(' re ')' stat
={ conout( $7, $2 );
bundle(3, $5, $2, " " );
}
| _WHILE CRS '(' re ')' stat BLEV
={ bundle(3, $6, $4, $2 );
conout( $$, $2 );
bundle(3, $4, $2, " " );
}
| fprefix CRS re ';' e ')' stat BLEV
={ bundle(5, $7, $5, "s.", $3, $2 );
conout( $$, $2 );
bundle(5, $1, "s.", $3, $2, " " );
}
| '~' LETTER '=' e
={ bundle(3,$4,"S",$2); }
;
EQOP : EQPL
={ $$ = (int) "+"; }
| EQMI
={ $$ = (int) "-"; }
| EQMUL
={ $$ = (int) "*"; }
| EQDIV
={ $$ = (int) "/"; }
| EQREM
={ $$ = (int) "%%"; }
| EQEXP
={ $$ = (int) "^"; }
;
fprefix : _FOR '(' e ';'
={ $$ = $3; }
;
BLEV :
={ --bindx; }
;
slist : stat
| slist tail stat
={ bundle(2, $1, $3 ); }
;
tail : '\n'
={ln++;}
| ';'
;
re : e EQ e
= bundle(3, $1, $3, "=" );
| e '<' e
= bundle(3, $1, $3, ">" );
| e '>' e
= bundle(3, $1, $3, "<" );
| e NE e
= bundle(3, $1, $3, "!=" );
| e GE e
= bundle(3, $1, $3, "!>" );
| e LE e
= bundle(3, $1, $3, "!<" );
| e
= bundle(2, $1, " 0!=" );
;
e : e '+' e
= bundle(3, $1, $3, "+" );
| e '-' e
= bundle(3, $1, $3, "-" );
| '-' e %prec UMINUS
= bundle(3, " 0", $2, "-" );
| e '*' e
= bundle(3, $1, $3, "*" );
| e '/' e
= bundle(3, $1, $3, "/" );
| e '%' e
= bundle(3, $1, $3, "%%" );
| e '^' e
= bundle(3, $1, $3, "^" );
| LETTER '[' e ']'
={ bundle(3,$3, ";", geta($1)); }
| LETTER INCR
= bundle(4, "l", $1, "d1+s", $1 );
| INCR LETTER
= bundle(4, "l", $2, "1+ds", $2 );
| DECR LETTER
= bundle(4, "l", $2, "1-ds", $2 );
| LETTER DECR
= bundle(4, "l", $1, "d1-s", $1 );
| LETTER '[' e ']' INCR
= bundle(7,$3,";",geta($1),"d1+",$3,":",geta($1));
| INCR LETTER '[' e ']'
= bundle(7,$4,";",geta($2),"1+d",$4,":",geta($2));
| LETTER '[' e ']' DECR
= bundle(7,$3,";",geta($1),"d1-",$3,":",geta($1));
| DECR LETTER '[' e ']'
= bundle(7,$4,";",geta($2),"1-d",$4,":",geta($2));
| SCALE INCR
= bundle(1,"Kd1+k");
| INCR SCALE
= bundle(1,"K1+dk");
| SCALE DECR
= bundle(1,"Kd1-k");
| DECR SCALE
= bundle(1,"K1-dk");
| BASE INCR
= bundle(1,"Id1+i");
| INCR BASE
= bundle(1,"I1+di");
| BASE DECR
= bundle(1,"Id1-i");
| DECR BASE
= bundle(1,"I1-di");
| OBASE INCR
= bundle(1,"Od1+o");
| INCR OBASE
= bundle(1,"O1+do");
| OBASE DECR
= bundle(1,"Od1-o");
| DECR OBASE
= bundle(1,"O1-do");
| LETTER '(' cargs ')'
= bundle(4, $3, "l", getf($1), "x" );
| LETTER '(' ')'
= bundle(3, "l", getf($1), "x" );
| cons
={ bundle(2, " ", $1 ); }
| DOT cons
={ bundle(2, " .", $2 ); }
| cons DOT cons
={ bundle(4, " ", $1, ".", $3 ); }
| cons DOT
={ bundle(3, " ", $1, "." ); }
| DOT
={ $$ = (int) "l."; }
| LETTER
= { bundle(2, "l", $1 ); }
| LETTER '=' e
={ bundle(3, $3, "ds", $1 ); }
| LETTER EQOP e %prec '='
={ bundle(6, "l", $1, $3, $2, "ds", $1 ); }
| LETTER '[' e ']' '=' e
= { bundle(5,$6,"d",$3,":",geta($1)); }
| LETTER '[' e ']' EQOP e
= { bundle(9,$3,";",geta($1),$6,$5,"d",$3,":",geta($1)); }
| LENGTH '(' e ')'
= bundle(2,$3,"Z");
| SCALE '(' e ')'
= bundle(2,$3,"X"); /* must be before '(' e ')' */
| '(' e ')'
= { $$ = $2; }
| '?'
={ bundle(1, "?" ); }
| SQRT '(' e ')'
={ bundle(2, $3, "v" ); }
| '~' LETTER
={ bundle(2,"L",$2); }
| SCALE '=' e
= bundle(2,$3,"dk");
| SCALE EQOP e %prec '='
= bundle(4,"K",$3,$2,"dk");
| BASE '=' e
= bundle(2,$3,"di");
| BASE EQOP e %prec '='
= bundle(4,"I",$3,$2,"di");
| OBASE '=' e
= bundle(2,$3,"do");
| OBASE EQOP e %prec '='
= bundle(4,"O",$3,$2,"do");
| SCALE
= bundle(1,"K");
| BASE
= bundle(1,"I");
| OBASE
= bundle(1,"O");
;
cargs : eora
| cargs ',' eora
= bundle(2, $1, $3 );
;
eora: e
| LETTER '[' ']'
=bundle(2,"l",geta($1));
;
cons : constant
={ *cp++ = '\0'; }
constant:
'_'
={ $$ = (int) cp; *cp++ = '_'; }
| DIGIT
={ $$ = (int) cp; *cp++ = $1; }
| constant DIGIT
={ *cp++ = $2; }
;
CRS :
={ $$ = (int) cp; *cp++ = crs++; *cp++ = '\0';
if(crs == '[')crs+=3;
if(crs == 'a')crs='{';
if(crs >= 0241){yyerror("program too big");
getout();
}
bstack[bindx++] = lev++; }
;
def : _DEFINE LETTER '('
={ $$ = (int) getf($2);
pre = (int*) "";
post = (int*) "";
lev = 1;
bstack[bindx=0] = 0;
}
;
dargs :
| lora
={ pp( $1 ); }
| dargs ',' lora
={ pp( $3 ); }
;
dlets : lora
={ tp($1); }
| dlets ',' lora
={ tp($3); }
;
lora : LETTER
| LETTER '[' ']'
={ $$ = (int) geta($1); }
;
%%
# define error 256
int peekc = -1;
int sargc;
int ifile;
char **sargv;
char funtab[52] = {
01,0,02,0,03,0,04,0,05,0,06,0,07,0,010,0,011,0,012,0,013,0,014,0,015,0,016,0,017,0,
020,0,021,0,022,0,023,0,024,0,025,0,026,0,027,0,030,0,031,0,032,0 };
char atab[52] = {
0241,0,0242,0,0243,0,0244,0,0245,0,0246,0,0247,0,0250,0,0251,0,0252,0,0253,0,
0254,0,0255,0,0256,0,0257,0,0260,0,0261,0,0262,0,0263,0,0264,0,0265,0,0266,0,
0267,0,0270,0,0271,0,0272,0};
char *letr[26] = {
"a","b","c","d","e","f","g","h","i","j",
"k","l","m","n","o","p","q","r","s","t",
"u","v","w","x","y","z" } ;
char *dot = { "." };
yylex(){
int c, ch;
restart:
c = getch();
peekc = -1;
while( c == ' ' || c == '\t' ) c = getch();
if(c == '\\'){
getch();
goto restart;
}
if( c<= 'z' && c >= 'a' ) {
/* look ahead to look for reserved words */
peekc = getch();
if( peekc >= 'a' && peekc <= 'z' ){ /* must be reserved word */
if( c=='i' && peekc=='f' ){ c=_IF; goto skip; }
if( c=='w' && peekc=='h' ){ c=_WHILE; goto skip; }
if( c=='f' && peekc=='o' ){ c=_FOR; goto skip; }
if( c=='s' && peekc=='q' ){ c=SQRT; goto skip; }
if( c=='r' && peekc=='e' ){ c=_RETURN; goto skip; }
if( c=='b' && peekc=='r' ){ c=_BREAK; goto skip; }
if( c=='d' && peekc=='e' ){ c=_DEFINE; goto skip; }
if( c=='s' && peekc=='c' ){ c= SCALE; goto skip; }
if( c=='b' && peekc=='a' ){ c=BASE; goto skip; }
if( c=='i' && peekc == 'b'){ c=BASE; goto skip; }
if( c=='o' && peekc=='b' ){ c=OBASE; goto skip; }
if( c=='d' && peekc=='i' ){ c=FFF; goto skip; }
if( c=='a' && peekc=='u' ){ c=_AUTO; goto skip; }
if( c == 'l' && peekc=='e'){ c=LENGTH; goto skip; }
if( c == 'q' && peekc == 'u'){getout();}
/* could not be found */
return( error );
skip: /* skip over rest of word */
peekc = -1;
while( (ch = getch()) >= 'a' && ch <= 'z' );
peekc = ch;
return( c );
}
/* usual case; just one single letter */
yylval = (int) letr[c-'a'];
return( LETTER );
}
if( c>= '0' && c <= '9' || c>= 'A' && c<= 'F' ){
yylval = c;
return( DIGIT );
}
switch( c ){
case '.': return( DOT );
case '=':
switch( peekc = getch() ){
case '=': c=EQ; goto gotit;
case '+': c=EQPL; goto gotit;
case '-': c=EQMI; goto gotit;
case '*': c=EQMUL; goto gotit;
case '/': c=EQDIV; goto gotit;
case '%': c=EQREM; goto gotit;
case '^': c=EQEXP; goto gotit;
default: return( '=' );
gotit: peekc = -1; return(c);
}
case '+': return( cpeek( '+', INCR, cpeek( '=', EQPL, '+') ) );
case '-': return( cpeek( '-', DECR, cpeek( '=', EQMI, '-') ) );
case '<': return( cpeek( '=', LE, '<' ) );
case '>': return( cpeek( '=', GE, '>' ) );
case '!': return( cpeek( '=', NE, '!' ) );
case '/':
if((peekc = getch()) == '*'){
peekc = -1;
while((getch() != '*') || ((peekc = getch()) != '/'));
peekc = -1;
goto restart;
}
else if (peekc == '=') {
c=EQDIV;
goto gotit;
}
else return(c);
case '*':
return( cpeek( '=', EQMUL, '*' ) );
case '%':
return( cpeek( '=', EQREM, '%' ) );
case '^':
return( cpeek( '=', EQEXP, '^' ) );
case '"':
yylval = (int) str;
while((c=getch()) != '"'){*str++ = c;
if(str >= &string[999]){yyerror("string space exceeded");
getout();
}
}
*str++ = '\0';
return(QSTR);
default: return( c );
}
}
cpeek( c, yes, no ){
if( (peekc=getch()) != c ) return( no );
else {
peekc = -1;
return( yes );
}
}
getch(){
int ch;
loop:
ch = (peekc < 0) ? getc(in) : peekc;
peekc = -1;
if(ch != EOF)return(ch);
if(++ifile > sargc){
if(ifile >= sargc+2)getout();
in = stdin;
ln = 0;
goto loop;
}
fclose(in);
if((in = fopen(sargv[ifile],"r")) != NULL){
ln = 0;
ss = sargv[ifile];
goto loop;
}
yyerror("cannot open input file");
}
# define b_sp_max 3000
int b_space [ b_sp_max ];
int * b_sp_nxt = { b_space };
int bdebug = 0;
bundle(a){
int i, *p, *q;
p = &a;
i = *p++;
q = b_sp_nxt;
if (bdebug) printf("bundle %d elements at %p\n", i, q);
while(i-- > 0){
if( b_sp_nxt >= & b_space[b_sp_max] ) yyerror( "bundling space exceeded" );
* b_sp_nxt++ = *p++;
}
* b_sp_nxt++ = 0;
yyval = (int) q;
return( (int) q );
}
routput(p) int *p; {
if( bdebug ) printf("routput(%p)\n", p );
if( p >= &b_space[0] && p < &b_space[b_sp_max]){
/* part of a bundle */
while( *p != 0 ) routput( *p++ );
}
else printf( "%s", (char*) p ); /* character string */
}
output( p ) int *p; {
routput( p );
b_sp_nxt = & b_space[0];
printf( "\n" );
fflush(stdout);
cp = cary;
crs = rcrs;
}
conout( p, s ) int *p; char *s; {
printf("[");
routput( p );
printf("]s%s\n", s );
fflush(stdout);
lev--;
}
yyerror( s ) char *s; {
if(ifile > sargc)ss="teletype";
printf("c[%s on line %d, %s]pc\n", s ,ln+1,ss);
fflush(stdout);
cp = cary;
crs = rcrs;
bindx = 0;
lev = 0;
b_sp_nxt = &b_space[0];
}
pp( s ) char *s; {
/* puts the relevant stuff on pre and post for the letter s */
bundle(3, "S", s, pre );
pre = (int*) yyval;
bundle(4, post, "L", s, "s." );
post = (int*) yyval;
}
tp( s ) char *s; { /* same as pp, but for temps */
bundle(3, "0S", s, pre );
pre = (int*) yyval;
bundle(4, post, "L", s, "s." );
post = (int*) yyval;
}
yyinit(argc,argv) int argc; char *argv[];{
signal( 2, SIG_IGN ); /* ignore all interrupts */
sargv=argv;
sargc= -- argc;
if(sargc == 0)in=stdin;
else if((in = fopen(sargv[1],"r")) == NULL) {
yyerror("cannot open input file");
in = stdin;
}
ifile = 1;
ln = 0;
ss = sargv[1];
}
int *getout(){
printf("q");
fflush(stdout);
exit(0);
}
int *
getf(p) char *p;{
return (int*) &funtab[2 * (*p - 0141)];
}
int *
geta(p) char *p;{
return (int*) &atab[2 * (*p - 0141)];
}
main(argc, argv)
char **argv;
{
int p[2];
if (argc > 1 && *argv[1] == '-') {
if((argv[1][1] == 'd')||(argv[1][1] == 'c')){
yyinit(--argc, ++argv);
yyparse();
exit(0);
}
if(argv[1][1] != 'l'){
printf("unrecognizable argument\n");
fflush(stdout);
exit(0);
}
argv[1] = "/usr/share/misc/lib.b";
}
pipe(p);
if (fork()==0) {
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
yyinit(argc, argv);
yyparse();
exit(0);
}
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
execl("/bin/dc", "dc", "-", (char*) 0);
execl("/usr/bin/dc", "dc", "-", (char*) 0);
}
+208
View File
@@ -0,0 +1,208 @@
#include <stdio.h>
#include <stdlib.h>
char dayw[] = {
" S M Tu W Th F S"
};
char *smon[]= {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December",
};
char string[432];
main(argc, argv)
char *argv[];
{
register y, i, j;
int m;
if(argc < 2) {
printf("usage: cal [month] year\n");
exit(0);
}
if(argc == 2)
goto xlong;
/*
* print out just month
*/
m = number(argv[1]);
if(m<1 || m>12)
goto badarg;
y = number(argv[2]);
if(y<1 || y>9999)
goto badarg;
printf(" %s %u\n", smon[m-1], y);
printf("%s\n", dayw);
cal(m, y, string, 24);
for(i=0; i<6*24; i+=24)
pstr(string+i, 24);
exit(0);
/*
* print out complete year
*/
xlong:
y = number(argv[1]);
if(y<1 || y>9999)
goto badarg;
printf("\n\n\n");
printf(" %u\n", y);
printf("\n");
for(i=0; i<12; i+=3) {
for(j=0; j<6*72; j++)
string[j] = '\0';
printf(" %.3s", smon[i]);
printf(" %.3s", smon[i+1]);
printf(" %.3s\n", smon[i+2]);
printf("%s %s %s\n", dayw, dayw, dayw);
cal(i+1, y, string, 72);
cal(i+2, y, string+23, 72);
cal(i+3, y, string+46, 72);
for(j=0; j<6*72; j+=72)
pstr(string+j, 72);
}
printf("\n\n\n");
exit(0);
badarg:
printf("Bad argument\n");
}
number(str)
char *str;
{
register n, c;
register char *s;
n = 0;
s = str;
while(c = *s++) {
if(c<'0' || c>'9')
return(0);
n = n*10 + c-'0';
}
return(n);
}
pstr(str, n)
char *str;
{
register i;
register char *s;
s = str;
i = n;
while(i--)
if(*s++ == '\0')
s[-1] = ' ';
i = n+1;
while(i--)
if(*--s != ' ')
break;
s[1] = '\0';
printf("%s\n", str);
}
char mon[] = {
0,
31, 29, 31, 30,
31, 30, 31, 31,
30, 31, 30, 31,
};
cal(m, y, p, w)
char *p;
{
register d, i;
register char *s;
s = p;
d = jan1(y);
mon[2] = 29;
mon[9] = 30;
switch((jan1(y+1)+7-d)%7) {
/*
* non-leap year
*/
case 1:
mon[2] = 28;
break;
/*
* 1752
*/
default:
mon[9] = 19;
break;
/*
* leap year
*/
case 2:
;
}
for(i=1; i<m; i++)
d += mon[i];
d %= 7;
s += 3*d;
for(i=1; i<=mon[m]; i++) {
if(i==3 && mon[m]==19) {
i += 11;
mon[m] += 11;
}
if(i > 9)
*s = i/10+'0';
s++;
*s++ = i%10+'0';
s++;
if(++d == 7) {
d = 0;
s = p+w;
p = s;
}
}
}
/*
* return day of the week
* of jan 1 of given year
*/
jan1(yr)
{
register y, d;
/*
* normal gregorian calendar
* one extra day per four years
*/
y = yr;
d = 4+y+(y+3)/4;
/*
* julian calendar
* regular gregorian
* less three days per 400
*/
if(y > 1800) {
d -= (y-1701)/100;
d += (y-1601)/400;
}
/*
* great calendar changeover instant
*/
if(y > 1752)
d += 3;
return(d%7);
}
+217
View File
@@ -0,0 +1,217 @@
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/*
* Concatenate files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
/* #define OPTSIZE BUFSIZ /* define this only if not 4.2 BSD or beyond */
int bflg, eflg, nflg, sflg, tflg, uflg, vflg;
int spaced, col, lno, inlin, ibsize, obsize;
main(argc, argv)
char **argv;
{
int fflg = 0;
register FILE *fi;
register c;
int dev, ino = -1;
struct stat statb;
int retval = 0;
lno = 1;
for( ; argc>1 && argv[1][0]=='-'; argc--,argv++) {
switch(argv[1][1]) {
case 0:
break;
case 'u':
setbuf(stdout, (char *)NULL);
uflg++;
continue;
case 'n':
nflg++;
continue;
case 'b':
bflg++;
nflg++;
continue;
case 'v':
vflg++;
continue;
case 's':
sflg++;
continue;
case 'e':
eflg++;
vflg++;
continue;
case 't':
tflg++;
vflg++;
continue;
}
break;
}
if (fstat(fileno(stdout), &statb) == 0) {
statb.st_mode &= S_IFMT;
if (statb.st_mode!=S_IFCHR && statb.st_mode!=S_IFBLK) {
dev = statb.st_dev;
ino = statb.st_ino;
}
#ifndef OPTSIZE
obsize = statb.st_blksize;
#endif
}
else
obsize = 0;
if (argc < 2) {
argc = 2;
fflg++;
}
while (--argc > 0) {
if (fflg || (*++argv)[0]=='-' && (*argv)[1]=='\0')
fi = stdin;
else {
if ((fi = fopen(*argv, "r")) == NULL) {
perror(*argv);
retval = 1;
continue;
}
}
if (fstat(fileno(fi), &statb) == 0) {
if ((statb.st_mode & S_IFMT) == S_IFREG &&
statb.st_dev==dev && statb.st_ino==ino) {
fprintf(stderr, "cat: input %s is output\n",
fflg?"-": *argv);
fclose(fi);
retval = 1;
continue;
}
#ifndef OPTSIZE
ibsize = statb.st_blksize;
#endif
}
else
ibsize = 0;
if (nflg||sflg||vflg)
copyopt(fi);
else if (uflg) {
while ((c = getc(fi)) != EOF)
putchar(c);
} else
retval |= fastcat(fileno(fi)); /* no flags specified */
if (fi!=stdin)
fclose(fi);
else
clearerr(fi); /* reset sticky eof */
if (ferror(stdout)) {
fprintf(stderr, "cat: output write error\n");
retval = 1;
break;
}
}
exit(retval);
}
copyopt(f)
register FILE *f;
{
register int c;
top:
c = getc(f);
if (c == EOF)
return;
if (c == '\n') {
if (inlin == 0) {
if (sflg && spaced)
goto top;
spaced = 1;
}
if (nflg && bflg==0 && inlin==0)
printf("%6d\t", lno++);
if (eflg)
putchar('$');
putchar('\n');
inlin = 0;
goto top;
}
if (nflg && inlin == 0)
printf("%6d\t", lno++);
inlin = 1;
if (vflg) {
if (tflg==0 && c == '\t')
putchar(c);
else {
if (c > 0177) {
printf("M-");
c &= 0177;
}
if (c < ' ')
printf("^%c", c+'@');
else if (c == 0177)
printf("^?");
else
putchar(c);
}
} else
putchar(c);
spaced = 0;
goto top;
}
fastcat(fd)
register int fd;
{
register int buffsize, n, nwritten, offset;
register char *buff;
struct stat statbuff;
#ifndef OPTSIZE
if (obsize)
buffsize = obsize; /* common case, use output blksize */
else if (ibsize)
buffsize = ibsize;
else
buffsize = BUFSIZ;
#else
buffsize = OPTSIZE;
#endif
if ((buff = malloc(buffsize)) == NULL) {
perror("cat: no memory");
return (1);
}
/*
* Note that on some systems (V7), very large writes to a pipe
* return less than the requested size of the write.
* In this case, multiple writes are required.
*/
while ((n = read(fd, buff, buffsize)) > 0) {
offset = 0;
do {
nwritten = write(fileno(stdout), &buff[offset], n);
if (nwritten <= 0) {
perror("cat: write error");
exit(2);
}
offset += nwritten;
} while ((n -= nwritten) > 0);
}
free(buff);
if (n < 0) {
perror("cat: read error");
return (1);
}
return (0);
}
+380
View File
@@ -0,0 +1,380 @@
#include <stdio.h>
int slevel[10];
int clevel = 0;
int spflg[20][10];
int sind[20][10];
int siflev[10];
int sifflg[10];
int iflev = 0;
int ifflg = -1;
int level = 0;
int ind[10] = {
0,0,0,0,0,0,0,0,0,0 };
int eflg = 0;
int paren = 0;
int pflg[10] = {
0,0,0,0,0,0,0,0,0,0 };
char lchar;
char pchar;
int aflg = 0;
int ct;
int stabs[20][10];
int qflg = 0;
char *wif[] = {
"if",0};
char *welse[] = {
"else",0};
char *wfor[] = {
"for",0};
char *wds[] = {
"case","default",0};
int j = 0;
char string[200];
char cc;
int sflg = 1;
int peek = -1;
int tabs = 0;
int lastchar;
int c;
int getstr();
putstr()
{
if(j > 0){
if(sflg != 0){
ptabs();
sflg = 0;
if(aflg == 1){
aflg = 0;
if(tabs > 0)printf(" ");
}
}
string[j] = '\0';
printf("%s",string);
j = 0;
}
else{
if(sflg != 0){
sflg = 0;
aflg = 0;
}
}
}
main(argc, argv)
int argc;
char argv[];
{
while((c = getch()) != EOF){
switch(c){
case ' ':
case '\t':
if(lookup(welse) == 1){
gotelse();
if(sflg == 0 || j > 0)string[j++] = c;
putstr();
sflg = 0;
continue;
}
if(sflg == 0 || j > 0)string[j++] = c;
continue;
case '\n':
if((eflg = lookup(welse)) == 1)gotelse();
putstr();
printf("\n");
sflg = 1;
if(eflg == 1){
pflg[level]++;
tabs++;
}
else
if(pchar == lchar)
aflg = 1;
continue;
case '{':
if(lookup(welse) == 1)gotelse();
siflev[clevel] = iflev;
sifflg[clevel] = ifflg;
iflev = ifflg = 0;
clevel++;
if(sflg == 1 && pflg[level] != 0){
pflg[level]--;
tabs--;
}
string[j++] = c;
putstr();
getnl();
putstr();
printf("\n");
tabs++;
sflg = 1;
if(pflg[level] > 0){
ind[level] = 1;
level++;
slevel[level] = clevel;
}
continue;
case '}':
clevel--;
if((iflev = siflev[clevel]-1) < 0)iflev = 0;
ifflg = sifflg[clevel];
if(pflg[level] >0 && ind[level] == 0){
tabs -= pflg[level];
pflg[level] = 0;
}
putstr();
tabs--;
ptabs();
if((peek = getch()) == ';'){
printf("%c;",c);
peek = -1;
}
else printf("%c",c);
getnl();
putstr();
printf("\n");
sflg = 1;
if(clevel < slevel[level])if(level > 0)level--;
if(ind[level] != 0){
tabs -= pflg[level];
pflg[level] = 0;
ind[level] = 0;
}
continue;
case '"':
case '\'':
string[j++] = c;
while((cc = getch()) != c){
string[j++] = cc;
if(cc == '\\'){
string[j++] = getch();
}
if(cc == '\n'){
putstr();
sflg = 1;
}
}
string[j++] = cc;
if(getnl() == 1){
lchar = cc;
peek = '\n';
}
continue;
case ';':
string[j++] = c;
putstr();
if(pflg[level] > 0 && ind[level] == 0){
tabs -= pflg[level];
pflg[level] = 0;
}
getnl();
putstr();
printf("\n");
sflg = 1;
if(iflev > 0)
if(ifflg == 1){iflev--;
ifflg = 0;
}
else iflev = 0;
continue;
case '\\':
string[j++] = c;
string[j++] = getch();
continue;
case '?':
qflg = 1;
string[j++] = c;
continue;
case ':':
string[j++] = c;
if(qflg == 1){
qflg = 0;
continue;
}
if(lookup(wds) == 0){
sflg = 0;
putstr();
}
else{
tabs--;
putstr();
tabs++;
}
if((peek = getch()) == ';'){
printf(";");
peek = -1;
}
getnl();
putstr();
printf("\n");
sflg = 1;
continue;
case '/':
string[j++] = c;
if((peek = getch()) != '*')continue;
string[j++] = peek;
peek = -1;
comment();
continue;
case ')':
paren--;
string[j++] = c;
putstr();
if(getnl() == 1){
peek = '\n';
if(paren != 0)aflg = 1;
else if(tabs > 0){
pflg[level]++;
tabs++;
ind[level] = 0;
}
}
continue;
case '#':
string[j++] = c;
while((cc = getch()) != '\n')string[j++] = cc;
string[j++] = cc;
sflg = 0;
putstr();
sflg = 1;
continue;
case '(':
string[j++] = c;
paren++;
if(lookup(wfor) == 1){
while((c = getstr()) != ';');
ct=0;
cont:
while((c = getstr()) != ')'){
if(c == '(') ct++;
}
if(ct != 0){
ct--;
goto cont;
}
paren--;
putstr();
if(getnl() == 1){
peek = '\n';
pflg[level]++;
tabs++;
ind[level] = 0;
}
continue;
}
if(lookup(wif) == 1){
putstr();
stabs[clevel][iflev] = tabs;
spflg[clevel][iflev] = pflg[level];
sind[clevel][iflev] = ind[level];
iflev++;
ifflg = 1;
}
continue;
default:
string[j++] = c;
if(c != ',')lchar = c;
}
}
}
ptabs()
{
int i;
for(i=0; i < tabs; i++)printf("\t");
}
getch()
{
if(peek < 0 && lastchar != ' ' && lastchar != '\t')pchar = lastchar;
lastchar = (peek<0) ? getc(stdin):peek;
peek = -1;
return(lastchar);
}
lookup(tab)
char *tab[];
{
char r;
int l,kk,k,i;
if(j < 1)return(0);
kk=0;
while(string[kk] == ' ')kk++;
for(i=0; tab[i] != 0; i++){
l=0;
for(k=kk;(r = tab[i][l++]) == string[k] && r != '\0';k++);
if(r == '\0' && (string[k] < 'a' || string[k] > 'z' || k >= j))return(1);
}
return(0);
}
getstr()
{
char ch;
beg:
if((ch = string[j++] = getch()) == '\\'){
string[j++] = getch();
goto beg;
}
if(ch == '\'' || ch == '"'){
while((cc = string[j++] = getch()) != ch)if(cc == '\\')string[j++] = getch();
goto beg;
}
if(ch == '\n'){
putstr();
aflg = 1;
goto beg;
}
else return(ch);
}
gotelse()
{
tabs = stabs[clevel][iflev];
pflg[level] = spflg[clevel][iflev];
ind[level] = sind[clevel][iflev];
ifflg = 1;
}
getnl()
{
while((peek = getch()) == '\t' || peek == ' '){
string[j++] = peek;
peek = -1;
}
if((peek = getch()) == '/'){
peek = -1;
if((peek = getch()) == '*'){
string[j++] = '/';
string[j++] = '*';
peek = -1;
comment();
}
else string[j++] = '/';
}
if((peek = getch()) == '\n'){
peek = -1;
return(1);
}
return(0);
}
comment()
{
int i = j;
while ((c = getch()) != EOF) {
string[j++] = c;
switch(c) {
case '/':
if (j > i + 1 && string[j-2] == '*')
return;
break;
case '\n':
putstr();
sflg = 1;
break;
}
}
}
+29
View File
@@ -0,0 +1,29 @@
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
OBJS = cc.o
CFLAGS += -Werror -Wall
CFLAGS += -DVERSSTR=\"1.0\" \
-DSTDINC=\"/include\" \
-DLIBDIR=\"/lib\" \
-DLIBEXECDIR=\"/libexec\" \
-DCRT0FILE=\"/lib/crt0.o\" \
-DCRT0FILE_PROFILE=\"/lib/mcrt0.o\"
all: cc
cc: $(OBJS)
${CC} ${LDFLAGS} -o cc.elf $(OBJS) ${LIBS}
${OBJDUMP} -S cc.elf > cc.dis
${SIZE} cc.elf
${ELF2AOUT} cc.elf $@ && rm cc.elf
clean:
rm -f *.o *.0 *.elf cc *.elf *.dis tags *~
install: all
install cc $(DESTDIR)/bin/
install cc $(DESTDIR)/bin/scc
install cc $(DESTDIR)/bin/srcc
+335
View File
@@ -0,0 +1,335 @@
.\" $Id: cc.1,v 1.16 2010/04/05 14:24:06 reed Exp $
.\" $NetBSD$
.\" $OpenBSD$
.\"
.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
.\" THIS SOFTWARE.
.\"
.Dd September 14, 2007
.Dt CC 1
.Os
.Sh NAME
.Nm cc
.Nd front-end to the C compiler
.Sh SYNOPSIS
.Nm
.Op Fl cEgkLMPOStvXx
.Op Fl fPIC
.Op Fl fpic
.Op Fl m Ns Ar option
.Op Fl nostartfiles
.Op Fl nostdinc
.Op Fl nostdlib
.Op Fl pg
.Op Fl pthread
.Op Fl static
.Op Fl B Ar prefix
.Op Fl D Ar macro[=value]
.Op Fl d Ar option
.Op Fl I Ar directory
.Op Fl include Ar path
.Op Fl isystem Ar path
.Op Fl o Ar outfile
.Op Fl Wl Ar flags
.Op Ar
.Sh DESCRIPTION
The
.Nm
utility provides a front-end to the
.Dq portable C compiler .
Multiple files may be given on the command line.
Unrecognized options are all sent directly to
.Xr ld 1 .
.Pp
.\" Brief description of its syntax:
Filenames that end with
.Sy \&.c
are passed via
.Xr cpp 1
\(->
.Xr ccom 1
\(->
.Xr as 1
\(->
.Xr ld 1 .
.Pp
Filenames that end with
.Sy \&.i
are passed via
.Xr ccom 1
\(->
.Xr as 1
\(->
.Xr ld 1 .
.Pp
Filenames that end with
.Sy \&.s
are passed via
.Xr as 1
\(->
.Xr ld 1 .
.Pp
Filenames that end with
.Sy \&.S
are passed via
.Xr cpp 1
\(->
.Xr as 1
\(->
.Xr ld 1 .
.Pp
Filenames that end with
.Sy \&.o
are passed directly to
.Xr ld 1 .
.Pp
.\"
The options are as follows:
.Bl -tag -width Ds
.It Fl B Ar prefix
Define alternate prefix path for
.Xr cpp 1 ,
.Xr ccom 1 ,
.Xr as 1 ,
or
.Xr ld 1
executables.
.\" TODO: provide an example of -B
.It Fl C
Passed to the
.Xr cpp 1
preprocessor to not discard comments.
.It Fl c
Only compile or assemble and then stop.
Do not link.
The resulting object output is saved
as a filename with a
.Dq \&.o
suffix unless
.Fl o
option is used.
Note: cannot be combined with
.Fl o
if multiple files are given.
.It Fl D Ar macro[=value]
Passed to the
.Xr cpp 1
preprocessor to define
.Ar macro .
.It Fl d Ar option
Passed to the
.Xr as 1
assembler.
.\" TODO: what is as -dfoo for?
.It Fl E
Stop after preprocessing with
.Xr cpp 1 .
Do not compile, assemble, or link.
Output is sent to standard output unless the
.Fl o
option is used.
.It Fl fPIC
Generate PIC code.
.\" TODO: document about avoiding machine-specific maximum size?
.It Fl fpic
Tells C compiler to generate PIC code
and tells assembler that PIC code has been generated.
.\" TODO: document difference between PIC and pic
.\" other -f GCC compatibility flags are ignored for now
.It Fl g
Send
.Fl g
flag to
.Xr ccom 1
to create debug output.
This unsets the
.Fl O
option.
.It Fl I Ar path
Passed to the
.Xr cpp 1
preprocessor to add header search directory to override system defaults.
.It Fl include Ar file
Tells the
.Xr cpp 1
preprocessor to include the
.Ar file
during preprocessing.
.It Fl isystem Ar path
Defines
.Ar path
as a system header directory for the
.Xr cpp 1
preprocessor.
.It Fl k
Generate PIC code.
See
.Fl fpic
option.
.It Fl L
TODO
.It Fl M
Pass
.Fl M
flag to
.Xr cpp 1
to generate dependencies for
.Xr make 1 .
.It Fl m Ns options
Target-dependent option.
.Bl -tag -width PowerPC
.It ARM
\-mlittle-endian \-mbig-endian \-mfpe=fpa \-mfpe=vpf \-msoft-float \-march=armv1 \-march=armv2 \-march=armv2a \-march=armv3 \-march=armv4 \-march=armv4t \-march=armv4tej \-march=armv5 \-march=armv6 \-march=armv6t2 \-march=armv6kz \-march=armv6k \-march=armv7
.It HPPA
.It i386
.It MIPS
\-mlittle-endian \-mbig-endian \-mhard-float \-msoft-float
.It PDP-10
.It PowerPC
.It Sparc64
.It VAX
.El
.It Fl nostartfiles
Do not link with the system startup files (crt0.c, etc.)
.It Fl nostdinc
Do not use the system include paths (/usr/include, etc.)
.It Fl nostdlib
Do not link with the system C library (libc).
.\" implies -nostartfiles ??
.It Fl O
Enable optimizations.
Currently passes
.Fl xdeljumps
and
.Fl xtemps
to
.Xr ccom 1 .
Note: this is unset if the
.Fl g
option is used.
.It Fl o Ar outfile
Save result to
.Ar outfile .
.It Fl P
TODO
.\" TODO: what is this?
.\" TODO: Looks like it does cpp only, but I couldn't get it to work for me.
.It Fl pg
Enable profiling on the generated executable.
.It Fl pthread
Defines
.Sy _PTHREADS
preprocessor directive for
.Xr cpp 1 .
Uses
.Sy \-lpthread
for the
.Xr ld 1
linker.
.It Fl S
Stop after compilation by
.Xr ccom 1 .
Do not assemble and do not link.
The resulting assembler-language output is saved
as a filename with a
.Dq \&.s
suffix unless the
.Fl o
option is used.
Note: cannot be combined with
.Fl o
if multiple files are given.
.It Fl static
Do not use dynamic linkage.
By default, it will link using the dynamic linker options
and/or shared objects for the platform.
.It Fl shared
Create a shared object of the result. Tells the linker not to
generate an executable.
.It Fl t
Passes
.Fl t
to
.Xr cpp 1
for traditional C preprocessor syntax.
.It Fl U Ar macro
Passes to the
.Xr cpp 1
preprocessor to remove the initial macro definition.
.It Fl v
Outputs the version of
.Nm
and shows what commands will be run with their command line arguments.
.It Fl Wl Ar flags
Options for the linker.
.\" what is ignored? llist?
.It Fl X
Don't remove temporary files on exit.
.It Fl x
May be used to give separate optimization flags to ccom, see
.Fl O
for options.
.It Fl x Ar c
Gcc compatibility option; specify that the language in use is
.Ar c .
.El
.Ss Predefined Macros
A few
macros are predefined by
.Nm
when sent to
.Xr cpp 1 .
.Bl -diag
.\" TODO:
.\" .It __ASSEMBLER__
.\" Defined if suffix is .S -- why not with .s? what does this mean?
.It __PCC__
Set to the major version of
.Xr pcc 1 .
These macros can be used to select code based on
.Xr pcc 1
compatibility.
See the
.Fl v
option.
.It __PCC_MINOR__
Set to the minor version.
.It __PCC_MINORMINOR__
Set to the minor-minor version \(em the number after the minor version.
.It _PTHREADS
Defined when
.Fl pthread
switch is used.
.El
.Pp
Also system- and/or machine-dependent macros may also be predefined;
for example:
.Dv __NetBSD__ ,
.Dv __ELF__ ,
and
.Dv __i386__ .
.Sh SEE ALSO
.Xr as 1 ,
.Xr ccom 1 ,
.Xr cpp 1 ,
.Xr ld 1
.Sh HISTORY
The
.Nm
command comes from the original Portable C Compiler by S. C. Johnson,
written in the late 70's.
.Pp
This product includes software developed or owned by Caldera
International, Inc.
+1423
View File
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
#
# Makefile for ccom
#
TOPSRC = $(shell cd ../../..; pwd)
include $(TOPSRC)/target.mk
#include $(TOPSRC)/cross.mk
#CFLAGS = -O -DCROSS
ARCHDIR = arch-mips
MIPDIR = mip
CFLAGS += -DGCC_COMPAT -DPCC_DEBUG -D_ISOC99_SOURCE -DYY_NO_INPUT -Dmach_mips -I. -I${MIPDIR} -I${ARCHDIR}
CFLAGS += -g -Werror -Wall
LDFLAGS += -g
OBJS1 = optim.o pftn.o scan.o trees.o cgram.o inline.o symtabs.o \
gcc_compat.o init.o local.o code.o stabs.o builtins.o
OBJS2 = match.o reader.o optim2.o regs.o local2.o order.o table.o
OBJS = $(OBJS1) $(OBJS2) compat.o common.o main.o external.o
MAN = ccom.0
MANSRC = ccom.1
all: ccom $(MAN)
ccom: ${OBJS}
${CC} ${LDFLAGS} -o ccom.elf ${OBJS} ${LIBS}
${OBJDUMP} -S ccom.elf > ccom.dis
${SIZE} ccom.elf
${ELF2AOUT} ccom.elf $@ && rm ccom.elf
ccom.0: ccom.1
${MANROFF} $< > $@
clean:
rm -f *.o *.0 *.elf ${MAN} ccom *.elf *.dis a.out *~ scan.c cgram.[ch] mkext
install: all
install ccom $(DESTDIR)/libexec/
cp ccom.0 $(DESTDIR)/share/man/cat1/
local.o: $(ARCHDIR)/local.c external.h
$(CC) $(CFLAGS) -c -o $@ $(ARCHDIR)/local.c
local2.o: $(ARCHDIR)/local2.c external.h
$(CC) $(CFLAGS) -c -o $@ $(ARCHDIR)/local2.c
code.o: $(ARCHDIR)/code.c external.h
$(CC) $(CFLAGS) -c -o $@ $(ARCHDIR)/code.c
order.o: $(ARCHDIR)/order.c external.h
$(CC) $(CFLAGS) -c -o $@ $(ARCHDIR)/order.c
table.o: $(ARCHDIR)/table.c external.h
$(CC) $(CFLAGS) -c -o $@ $(ARCHDIR)/table.c
match.o: $(MIPDIR)/match.c external.h
$(CC) $(CFLAGS) -c -o $@ $(MIPDIR)/match.c
reader.o: $(MIPDIR)/reader.c external.h
$(CC) $(CFLAGS) -c -o $@ $(MIPDIR)/reader.c
optim2.o: $(MIPDIR)/optim2.c external.h
$(CC) $(CFLAGS) -c -o $@ $(MIPDIR)/optim2.c
regs.o: $(MIPDIR)/regs.c external.h
$(CC) $(CFLAGS) -c -o $@ $(MIPDIR)/regs.c
cgram.o: cgram.c external.h
$(CC) $(CFLAGS) -c -o $@ cgram.c
scan.o: scan.c external.h
$(CC) $(CFLAGS) -c -o $@ scan.c
common.o: $(MIPDIR)/common.c external.h
$(CC) $(CFLAGS) -c -o $@ $(MIPDIR)/common.c
compat.o: $(MIPDIR)/compat.c external.h
$(CC) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.c
external.h external.c: ${MIPDIR}/mkext.c $(ARCHDIR)/table.c
gcc $(CFLAGS) -DMKEXT -o mkext ${MIPDIR}/mkext.c $(ARCHDIR)/table.c ${MIPDIR}/common.c
./mkext
trees.c: mip/pass2.h external.h
inline.c: external.h
init.c: external.h
pftn.c: external.h
gcc_compat.c: external.h
symtabs.c: external.h
stabs.c: external.h
main.c: external.h
pass1.h: external.h
pass2.h: external.h
cgram.c: cgram.y
$(YACC) $(YFLAGS) -d $<
mv y.tab.c cgram.c
mv y.tab.h cgram.h
scan.c: scan.l
$(LEX) $(LFLAGS) $<
mv lex.yy.c scan.c
optim2.o reader.o optim.o : external.h
pftn.o cgram.h: cgram.c
+889
View File
@@ -0,0 +1,889 @@
/* $Id: code.c,v 1.21 2009/02/08 16:07:52 ragge Exp $ */
/*
* Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Stuff for pass1.
*/
#include <assert.h>
#include "pass1.h"
#include "pass2.h"
int lastloc = -1;
static int rvnr;
/*
* Define everything needed to print out some data (or text).
* This means segment, alignment, visibility, etc.
*/
void
defloc(struct symtab *sp)
{
extern char *nextsect;
static char *loctbl[] = { "text", "data", "section .rodata" };
char *n;
TWORD t;
int s;
if (sp == NULL) {
lastloc = -1;
return;
}
t = sp->stype;
s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? PROG : DATA;
if (nextsect) {
printf("\t.section %s\n", nextsect);
nextsect = NULL;
s = -1;
} else if (s != lastloc)
printf("\t.%s\n", loctbl[s]);
lastloc = s;
while (ISARY(t))
t = DECREF(t);
if (t > UCHAR)
printf("\t.align %d\n", t > USHORT ? 4 : 2);
n = sp->soname ? sp->soname : exname(sp->sname);
#ifdef USE_GAS
if (ISFTN(t))
printf("\t.type %s,%%function\n", n);
#endif
if (sp->sclass == EXTDEF)
printf("\t.global %s\n", n);
if (ISFTN(t))
return;
if (sp->slevel == 0)
printf("%s:\n", n);
else
printf(LABFMT ":\n", sp->soffset);
}
/* Put a symbol in a temporary
* used by bfcode() and its helpers
*/
static void
putintemp(struct symtab *sym)
{
NODE *p;
p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
p = buildtree(ASSIGN, p, nametree(sym));
sym->soffset = regno(p->n_left);
sym->sflags |= STNODE;
ecomp(p);
}
/* setup a 64-bit parameter (double/ldouble/longlong)
* used by bfcode() */
static void
param_64bit(struct symtab *sym, int *argofsp, int dotemps)
{
int argofs = *argofsp;
NODE *p, *q;
int navail;
#if ALLONGLONG == 64
/* alignment */
++argofs;
argofs &= ~1;
*argofsp = argofs;
#endif
navail = NARGREGS - argofs;
if (navail < 2) {
/* half in and half out of the registers */
if (features(FEATURE_BIGENDIAN)) {
cerror("param_64bit");
p = q = NULL;
} else {
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(q) = R0 + argofs;
if (dotemps) {
q = block(SCONV, q, NIL,
ULONGLONG, 0, MKSUE(ULONGLONG));
p = nametree(sym);
p->n_type = ULONGLONG;
p->n_df = 0;
p->n_sue = MKSUE(ULONGLONG);
p = block(LS, p, bcon(32), ULONGLONG,
0, MKSUE(ULONGLONG));
q = block(PLUS, p, q, ULONGLONG,
0, MKSUE(ULONGLONG));
p = tempnode(0, ULONGLONG,
0, MKSUE(ULONGLONG));
sym->soffset = regno(p);
sym->sflags |= STNODE;
} else {
p = nametree(sym);
regno(p) = sym->soffset;
p->n_type = INT;
p->n_df = 0;
p->n_sue = MKSUE(INT);
}
}
p = buildtree(ASSIGN, p, q);
ecomp(p);
*argofsp = argofs + 2;
return;
}
q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
regno(q) = R0R1 + argofs;
if (dotemps) {
p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
sym->soffset = regno(p);
sym->sflags |= STNODE;
} else {
p = nametree(sym);
}
p = buildtree(ASSIGN, p, q);
ecomp(p);
*argofsp = argofs + 2;
}
/* setup a 32-bit param on the stack
* used by bfcode() */
static void
param_32bit(struct symtab *sym, int *argofsp, int dotemps)
{
NODE *p, *q;
q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
regno(q) = R0 + (*argofsp)++;
if (dotemps) {
p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
sym->soffset = regno(p);
sym->sflags |= STNODE;
} else {
p = nametree(sym);
}
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
/* setup a double param on the stack
* used by bfcode() */
static void
param_double(struct symtab *sym, int *argofsp, int dotemps)
{
NODE *p, *q, *t;
int tmpnr;
/*
* we have to dump the float from the general register
* into a temp, since the register allocator doesn't like
* floats to be in CLASSA. This may not work for -xtemps.
*/
t = tempnode(0, ULONGLONG, 0, MKSUE(ULONGLONG));
tmpnr = regno(t);
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
q->n_rval = R0R1 + (*argofsp)++;
p = buildtree(ASSIGN, t, q);
ecomp(p);
if (dotemps) {
sym->soffset = tmpnr;
sym->sflags |= STNODE;
} else {
q = tempnode(tmpnr, sym->stype, sym->sdf, sym->ssue);
p = nametree(sym);
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
}
/* setup a float param on the stack
* used by bfcode() */
static void
param_float(struct symtab *sym, int *argofsp, int dotemps)
{
NODE *p, *q, *t;
int tmpnr;
/*
* we have to dump the float from the general register
* into a temp, since the register allocator doesn't like
* floats to be in CLASSA. This may not work for -xtemps.
*/
t = tempnode(0, INT, 0, MKSUE(INT));
tmpnr = regno(t);
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
q->n_rval = R0 + (*argofsp)++;
p = buildtree(ASSIGN, t, q);
ecomp(p);
if (dotemps) {
sym->soffset = tmpnr;
sym->sflags |= STNODE;
} else {
q = tempnode(tmpnr, sym->stype, sym->sdf, sym->ssue);
p = nametree(sym);
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
}
/* setup the hidden pointer to struct return parameter
* used by bfcode() */
static void
param_retstruct(void)
{
NODE *p, *q;
p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->ssue);
rvnr = regno(p);
q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
regno(q) = R0;
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
/* setup struct parameter
* push the registers out to memory
* used by bfcode() */
static void
param_struct(struct symtab *sym, int *argofsp)
{
int argofs = *argofsp;
NODE *p, *q;
int navail;
int sz;
int off;
int num;
int i;
navail = NARGREGS - argofs;
sz = tsize(sym->stype, sym->sdf, sym->ssue) / SZINT;
off = ARGINIT/SZINT + argofs;
num = sz > navail ? navail : sz;
for (i = 0; i < num; i++) {
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(q) = R0 + argofs++;
p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(p) = SP;
p = block(PLUS, p, bcon(4*off++), INT, 0, MKSUE(INT));
p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
*argofsp = argofs;
}
/*
* Beginning-of-function code:
*
* 'sp' is an array of indices in symtab for the arguments
* 'cnt' is the number of arguments
*/
void
bfcode(struct symtab **sp, int cnt)
{
union arglist *usym;
int saveallargs = 0;
int i, argofs = 0;
/*
* Detect if this function has ellipses and save all
* argument registers onto stack.
*/
usym = cftnsp->sdf->dfun;
while (usym && usym->type != TNULL) {
if (usym->type == TELLIPSIS) {
saveallargs = 1;
break;
}
++usym;
}
/* if returning a structure, move the hidden argument into a TEMP */
if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
param_retstruct();
++argofs;
}
/* recalculate the arg offset and create TEMP moves */
for (i = 0; i < cnt; i++) {
if (sp[i] == NULL)
continue;
if ((argofs >= NARGREGS) && !xtemps)
break;
if (argofs > NARGREGS) {
putintemp(sp[i]);
} else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
param_struct(sp[i], &argofs);
} else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
param_64bit(sp[i], &argofs, xtemps && !saveallargs);
} else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
if (features(FEATURE_HARDFLOAT))
param_double(sp[i], &argofs,
xtemps && !saveallargs);
else
param_64bit(sp[i], &argofs,
xtemps && !saveallargs);
} else if (sp[i]->stype == FLOAT) {
if (features(FEATURE_HARDFLOAT))
param_float(sp[i], &argofs,
xtemps && !saveallargs);
else
param_32bit(sp[i], &argofs,
xtemps && !saveallargs);
} else {
param_32bit(sp[i], &argofs, xtemps && !saveallargs);
}
}
/* if saveallargs, save the rest of the args onto the stack */
while (saveallargs && argofs < NARGREGS) {
NODE *p, *q;
int off = ARGINIT/SZINT + argofs;
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(q) = R0 + argofs++;
p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(p) = FPREG;
p = block(PLUS, p, bcon(4*off), INT, 0, MKSUE(INT));
p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
}
/*
* End-of-Function code:
*/
void
efcode()
{
NODE *p, *q;
int tempnr;
if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
return;
/*
* At this point, the address of the return structure on
* has been FORCEd to RETREG, which is R0.
* We want to copy the contents from there to the address
* we placed into the tempnode "rvnr".
*/
/* move the pointer out of R0 to a tempnode */
q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
q->n_rval = R0;
p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue);
tempnr = regno(p);
p = buildtree(ASSIGN, p, q);
ecomp(p);
/* get the address from the tempnode */
q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->ssue);
q = buildtree(UMUL, q, NIL);
/* now, get the structure destination */
p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->ssue);
p = buildtree(UMUL, p, NIL);
/* struct assignment */
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
/*
* Beginning-of-code: finished generating function prologue
*
* by now, the automatics and register variables are allocated
*/
void
bccode()
{
SETOFF(autooff, SZINT);
}
/*
* End-of-job: called just before final exit.
*/
void
ejobcode(int flag )
{
#define _MKSTR(x) #x
#define MKSTR(x) _MKSTR(x)
#define OS MKSTR(TARGOS)
printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
}
/*
* Beginning-of-job: called before compilation starts
*
* Initialise data structures specific for the local machine.
*/
void
bjobcode()
{
}
/*
* Compute the alignment of object with type 't'.
*/
int
fldal(unsigned int t)
{
uerror("illegal field type");
return(ALINT);
}
/*
* fix up type of field p
*/
void
fldty(struct symtab *p)
{
}
/*
* Build target-dependent switch tree/table.
*
* Return 1 if successfull, otherwise return 0 and the
* target-independent tree will be used.
*/
int
mygenswitch(int num, TWORD type, struct swents **p, int n)
{
return 0;
}
/*
* Straighten a chain of CM ops so that the CM nodes
* only appear on the left node.
*
* CM CM
* CM CM CM b
* x y a b CM a
* x y
*/
static NODE *
straighten(NODE *p)
{
NODE *r = p->n_right;
if (p->n_op != CM || r->n_op != CM)
return p;
p->n_right = r->n_left;
r->n_left = p;
return r;
}
static NODE *
reverse1(NODE *p, NODE *a)
{
NODE *l = p->n_left;
NODE *r = p->n_right;
a->n_right = r;
p->n_left = a;
if (l->n_op == CM) {
return reverse1(l, p);
} else {
p->n_right = l;
return p;
}
}
/*
* Reverse a chain of CM ops
*/
static NODE *
reverse(NODE *p)
{
NODE *l = p->n_left;
NODE *r = p->n_right;
p->n_left = r;
if (l->n_op == CM)
return reverse1(l, p);
p->n_right = l;
return p;
}
/* push arg onto the stack */
/* called by moveargs() */
static NODE *
pusharg(NODE *p, int *regp)
{
NODE *q;
int sz;
/* convert to register size, if smaller */
sz = tsize(p->n_type, p->n_df, p->n_sue);
if (sz < SZINT)
p = block(SCONV, p, NIL, INT, 0, MKSUE(INT));
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(q) = SP;
if (szty(p->n_type) == 1) {
++(*regp);
q = block(MINUSEQ, q, bcon(4), INT, 0, MKSUE(INT));
} else {
(*regp) += 2;
q = block(MINUSEQ, q, bcon(8), INT, 0, MKSUE(INT));
}
q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_sue);
return buildtree(ASSIGN, q, p);
}
/* setup call stack with 32-bit argument */
/* called from moveargs() */
static NODE *
movearg_32bit(NODE *p, int *regp)
{
int reg = *regp;
NODE *q;
q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
regno(q) = reg++;
q = buildtree(ASSIGN, q, p);
*regp = reg;
return q;
}
/* setup call stack with 64-bit argument */
/* called from moveargs() */
static NODE *
movearg_64bit(NODE *p, int *regp)
{
int reg = *regp;
NODE *q, *r;
#if ALLONGLONG == 64
/* alignment */
++reg;
reg &= ~1;
*regp = reg;
#endif
if (reg > R3) {
q = pusharg(p, regp);
} else if (reg == R3) {
/* half in and half out of the registers */
r = tcopy(p);
if (!features(FEATURE_BIGENDIAN)) {
q = block(SCONV, p, NIL, INT, 0, MKSUE(INT));
q = movearg_32bit(q, regp); /* little-endian */
r = buildtree(RS, r, bcon(32));
r = block(SCONV, r, NIL, INT, 0, MKSUE(INT));
r = pusharg(r, regp); /* little-endian */
} else {
q = buildtree(RS, p, bcon(32));
q = block(SCONV, q, NIL, INT, 0, MKSUE(INT));
q = movearg_32bit(q, regp); /* big-endian */
r = block(SCONV, r, NIL, INT, 0, MKSUE(INT));
r = pusharg(r, regp); /* big-endian */
}
q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_sue));
} else {
q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
regno(q) = R0R1 + (reg - R0);
q = buildtree(ASSIGN, q, p);
*regp = reg + 2;
}
return q;
}
/* setup call stack with float/double argument */
/* called from moveargs() */
static NODE *
movearg_float(NODE *p, int *regp)
{
NODE *q, *r;
TWORD ty = INCREF(p->n_type);
int tmpnr;
/*
* Floats are passed in the general registers for
* compatibily with libraries compiled to handle soft-float.
*/
if (xtemps) {
/* bounce on TOS */
r = block(REG, NIL, NIL, ty, p->n_df, p->n_sue);
regno(r) = SP;
r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_sue);
r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_sue);
r = buildtree(ASSIGN, r, p);
ecomp(r);
/* bounce into temp */
r = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT));
regno(r) = SP;
r = block(PLUS, r, bcon(-8), PTR+INT, 0, MKSUE(INT));
r = block(UMUL, r, NIL, INT, 0, MKSUE(INT));
q = tempnode(0, INT, 0, MKSUE(INT));
tmpnr = regno(q);
r = buildtree(ASSIGN, q, r);
ecomp(r);
} else {
/* copy directly into temp */
q = tempnode(0, p->n_type, p->n_df, p->n_sue);
tmpnr = regno(q);
r = buildtree(ASSIGN, q, p);
ecomp(r);
}
/* copy from temp to register parameter */
r = tempnode(tmpnr, INT, 0, MKSUE(INT));
q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(q) = (*regp)++;
p = buildtree(ASSIGN, q, r);
return p;
}
/* setup call stack with float/double argument */
/* called from moveargs() */
static NODE *
movearg_double(NODE *p, int *regp)
{
NODE *q, *r;
TWORD ty = INCREF(p->n_type);
int tmpnr;
if (xtemps) {
/* bounce on TOS */
r = block(REG, NIL, NIL, ty, p->n_df, p->n_sue);
regno(r) = SP;
r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_sue);
r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_sue);
r = buildtree(ASSIGN, r, p);
ecomp(r);
/* bounce into temp */
r = block(REG, NIL, NIL, PTR+LONGLONG, 0, MKSUE(LONGLONG));
regno(r) = SP;
r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, MKSUE(LONGLONG));
r = block(UMUL, r, NIL, LONGLONG, 0, MKSUE(LONGLONG));
q = tempnode(0, LONGLONG, 0, MKSUE(LONGLONG));
tmpnr = regno(q);
r = buildtree(ASSIGN, q, r);
ecomp(r);
} else {
/* copy directly into temp */
q = tempnode(0, p->n_type, p->n_df, p->n_sue);
tmpnr = regno(q);
r = buildtree(ASSIGN, q, p);
ecomp(r);
}
/* copy from temp to register parameter */
r = tempnode(tmpnr, LONGLONG, 0, MKSUE(LONGLONG));
q = block(REG, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG));
regno(q) = R0R1 - R0 + (*regp);
p = buildtree(ASSIGN, q, r);
(*regp) += 2;
return p;
}
/* setup call stack with a structure */
/* called from moveargs() */
static NODE *
movearg_struct(NODE *p, int *regp)
{
int reg = *regp;
NODE *l, *q, *t, *r;
int tmpnr;
int navail;
int num;
int sz;
int ty;
int i;
assert(p->n_op == STARG);
navail = NARGREGS - (reg - R0);
navail = navail < 0 ? 0 : navail;
sz = tsize(p->n_type, p->n_df, p->n_sue) / SZINT;
num = sz > navail ? navail : sz;
/* remove STARG node */
l = p->n_left;
nfree(p);
ty = l->n_type;
/*
* put it into a TEMP, rather than tcopy(), since the tree
* in p may have side-affects
*/
t = tempnode(0, ty, l->n_df, l->n_sue);
tmpnr = regno(t);
q = buildtree(ASSIGN, t, l);
/* copy structure into registers */
for (i = 0; i < num; i++) {
t = tempnode(tmpnr, ty, 0, MKSUE(PTR+ty));
t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
t = buildtree(UMUL, t, NIL);
r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
regno(r) = reg++;
r = buildtree(ASSIGN, r, t);
q = block(CM, q, r, INT, 0, MKSUE(INT));
}
/* put the rest of the structure on the stack */
for (i = num; i < sz; i++) {
t = tempnode(tmpnr, ty, 0, MKSUE(PTR+ty));
t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
t = buildtree(UMUL, t, NIL);
r = pusharg(t, &reg);
q = block(CM, q, r, INT, 0, MKSUE(INT));
}
q = reverse(q);
*regp = reg;
return q;
}
static NODE *
moveargs(NODE *p, int *regp)
{
NODE *r, **rp;
int reg;
if (p->n_op == CM) {
p->n_left = moveargs(p->n_left, regp);
r = p->n_right;
rp = &p->n_right;
} else {
r = p;
rp = &p;
}
reg = *regp;
if (reg > R3 && r->n_op != STARG) {
*rp = pusharg(r, regp);
} else if (r->n_op == STARG) {
*rp = movearg_struct(r, regp);
} else if (DEUNSIGN(r->n_type) == LONGLONG) {
*rp = movearg_64bit(r, regp);
} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
*rp = movearg_double(r, regp);
} else if (r->n_type == FLOAT) {
*rp = movearg_float(r, regp);
} else {
*rp = movearg_32bit(r, regp);
}
return straighten(p);
}
/*
* Fixup arguments to pass pointer-to-struct as first argument.
*
* called from funcode().
*/
static NODE *
retstruct(NODE *p)
{
NODE *l, *r, *t, *q;
TWORD ty;
l = p->n_left;
r = p->n_right;
ty = DECREF(l->n_type) - FTN;
// assert(tsize(ty, l->n_df, l->n_sue) == SZINT);
/* structure assign */
q = tempnode(0, ty, l->n_df, l->n_sue);
q = buildtree(ADDROF, q, NIL);
/* insert hidden assignment at beginning of list */
if (r->n_op != CM) {
p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_sue);
} else {
for (t = r; t->n_left->n_op == CM; t = t->n_left)
;
t->n_left = block(CM, q, t->n_left, INCREF(ty),
l->n_df, l->n_sue);
}
return p;
}
/*
* Called with a function call with arguments as argument.
* This is done early in buildtree() and only done once.
*/
NODE *
funcode(NODE *p)
{
int reg = R0;
if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) {
p = retstruct(p);
reg = R1;
}
p->n_right = moveargs(p->n_right, &reg);
if (p->n_right == NULL)
p->n_op += (UCALL - CALL);
return p;
}
+814
View File
@@ -0,0 +1,814 @@
/* $Id: local.c,v 1.23 2009/09/07 08:06:34 gmcgarry Exp $ */
/*
* Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* We define location operations which operate on the expression tree
* during the first pass (before sending to the backend for code generation.)
*/
#include <assert.h>
#include "pass1.h"
extern void defalign(int);
/*
* clocal() is called to do local transformations on
* an expression tree before being sent to the backend.
*/
NODE *
clocal(NODE *p)
{
struct symtab *q;
NODE *l, *r, *t;
int o;
int ty;
int tmpnr, isptrvoid = 0;
char *n;
o = p->n_op;
switch (o) {
case STASG:
l = p->n_left;
r = p->n_right;
if (r->n_op != STCALL && r->n_op != USTCALL)
return p;
/* assign left node as first argument to function */
nfree(p);
t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
l->n_rval = R0;
l = buildtree(ADDROF, l, NIL);
l = buildtree(ASSIGN, t, l);
if (r->n_right->n_op != CM) {
r->n_right = block(CM, l, r->n_right,
INT, 0, MKSUE(INT));
} else {
for (t = r->n_right; t->n_left->n_op == CM;
t = t->n_left)
;
t->n_left = block(CM, l, t->n_left,
INT, 0, MKSUE(INT));
}
return r;
case CALL:
case STCALL:
case USTCALL:
if (p->n_type == VOID)
break;
/*
* if the function returns void*, ecode() invokes
* delvoid() to convert it to uchar*.
* We just let this happen on the ASSIGN to the temp,
* and cast the pointer back to void* on access
* from the temp.
*/
if (p->n_type == PTR+VOID)
isptrvoid = 1;
r = tempnode(0, p->n_type, p->n_df, p->n_sue);
tmpnr = regno(r);
r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_sue);
p = tempnode(tmpnr, r->n_type, r->n_df, r->n_sue);
if (isptrvoid) {
p = block(PCONV, p, NIL, PTR+VOID,
p->n_df, MKSUE(PTR+VOID));
}
p = buildtree(COMOP, r, p);
break;
case NAME:
if ((q = p->n_sp) == NULL)
return p;
if (blevel == 0)
return p;
switch (q->sclass) {
case PARAM:
case AUTO:
/* fake up a structure reference */
r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
r->n_lval = 0;
r->n_rval = FPREG;
p = stref(block(STREF, r, p, 0, 0, 0));
break;
case REGISTER:
p->n_op = REG;
p->n_lval = 0;
p->n_rval = q->soffset;
break;
case STATIC:
if (q->slevel > 0) {
p->n_lval = 0;
p->n_sp = q;
}
/* FALL-THROUGH */
default:
ty = p->n_type;
n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
if (strncmp(n, "__builtin", 9) == 0)
break;
p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_sue);
p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
break;
}
break;
case STNAME:
if ((q = p->n_sp) == NULL)
return p;
if (q->sclass != STNAME)
return p;
ty = p->n_type;
p = block(ADDROF, p, NIL, INCREF(ty),
p->n_df, p->n_sue);
p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
break;
case FORCE:
/* put return value in return reg */
p->n_op = ASSIGN;
p->n_right = p->n_left;
p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
p->n_left->n_rval = p->n_left->n_type == BOOL ?
RETREG(BOOL_TYPE) : RETREG(p->n_type);
break;
case PMCONV:
case PVCONV:
nfree(p);
return buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
case SCONV:
l = p->n_left;
if (p->n_type == l->n_type) {
nfree(p);
return l;
}
if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
if (p->n_type != FLOAT && p->n_type != DOUBLE &&
l->n_type != FLOAT && l->n_type != DOUBLE &&
l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
if (l->n_op == NAME || l->n_op == UMUL ||
l->n_op == TEMP) {
l->n_type = p->n_type;
nfree(p);
return l;
}
}
}
if (l->n_op == ICON) {
CONSZ val = l->n_lval;
if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
switch (p->n_type) {
case BOOL:
l->n_lval = l->n_lval != 0;
break;
case CHAR:
l->n_lval = (char)val;
break;
case UCHAR:
l->n_lval = val & 0377;
break;
case SHORT:
l->n_lval = (short)val;
break;
case USHORT:
l->n_lval = val & 0177777;
break;
case ULONG:
case UNSIGNED:
l->n_lval = val & 0xffffffff;
break;
case LONG:
case INT:
l->n_lval = (int)val;
break;
case LONGLONG:
l->n_lval = (long long)val;
break;
case ULONGLONG:
l->n_lval = val;
break;
case VOID:
break;
case LDOUBLE:
case DOUBLE:
case FLOAT:
l->n_op = FCON;
l->n_dcon = val;
break;
default:
cerror("unknown type %d", l->n_type);
}
l->n_type = p->n_type;
l->n_sue = MKSUE(p->n_type);
nfree(p);
return l;
} else if (p->n_op == FCON) {
l->n_lval = l->n_dcon;
l->n_sp = NULL;
l->n_op = ICON;
l->n_type = p->n_type;
l->n_sue = MKSUE(p->n_type);
nfree(p);
return clocal(l);
}
if ((DEUNSIGN(p->n_type) == CHAR ||
DEUNSIGN(p->n_type) == SHORT) &&
(l->n_type == FLOAT || l->n_type == DOUBLE ||
l->n_type == LDOUBLE)) {
p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
p->n_left->n_type = INT;
return p;
}
break;
case PCONV:
l = p->n_left;
if (l->n_op == ICON) {
l->n_lval = (unsigned)l->n_lval;
goto delp;
}
if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
p->n_left = block(SCONV, l, NIL,
UNSIGNED, 0, MKSUE(UNSIGNED));
break;
}
if (l->n_op == SCONV)
break;
if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
goto delp;
if (p->n_type > BTMASK && l->n_type > BTMASK)
goto delp;
break;
delp:
l->n_type = p->n_type;
l->n_qual = p->n_qual;
l->n_df = p->n_df;
l->n_sue = p->n_sue;
nfree(p);
p = l;
break;
}
return p;
}
/*
* Called before sending the tree to the backend.
*/
void
myp2tree(NODE *p)
{
struct symtab *sp;
if (p->n_op != FCON)
return;
#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
sp = IALLOC(sizeof(struct symtab));
sp->sclass = STATIC;
sp->ssue = MKSUE(p->n_type);
sp->slevel = 1; /* fake numeric label */
sp->soffset = getlab();
sp->sflags = 0;
sp->stype = p->n_type;
sp->squal = (CON >> TSHIFT);
defloc(sp);
ninval(0, sp->ssue->suesize, p);
p->n_op = NAME;
p->n_lval = 0;
p->n_sp = sp;
}
/*
* Called during the first pass to determine if a NAME can be addressed.
*
* Return nonzero if supported, otherwise return 0.
*/
int
andable(NODE *p)
{
if (blevel == 0)
return 1;
if (ISFTN(p->n_type))
return 1;
return 0;
}
/*
* Called just after function arguments are built. Re-initialize the
* offset of the arguments on the stack.
* Is this necessary anymore? bfcode() is called immediately after.
*/
void
cendarg()
{
autooff = AUTOINIT;
}
/*
* Return 1 if a variable of type 't' is OK to put in register.
*/
int
cisreg(TWORD t)
{
if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
return 0; /* not yet */
return 1;
}
/*
* Used for generating pointer offsets into structures and arrays.
*
* For a pointer of type 't', generate an the offset 'off'.
*/
NODE *
offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
{
return bcon(off/SZCHAR);
}
/*
* Allocate bits from the stack for dynamic-sized arrays.
*
* 'p' is the tree which represents the type being allocated.
* 'off' is the number of 'p's to be allocated.
* 't' is the storeable node where the address is written.
*/
void
spalloc(NODE *t, NODE *p, OFFSZ off)
{
NODE *sp;
p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
/* sub the size from sp */
sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
sp->n_lval = 0;
sp->n_rval = SP;
ecomp(buildtree(MINUSEQ, sp, p));
/* save the address of sp */
sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
sp->n_lval = 0;
sp->n_rval = SP;
t->n_type = sp->n_type;
ecomp(buildtree(ASSIGN, t, sp));
}
/*
* Print out a string of characters.
* Assume that the assembler understands C-style escape
* sequences.
*/
void
instring(struct symtab *sp)
{
char *s, *str;
defloc(sp);
str = sp->sname;
/* be kind to assemblers and avoid long strings */
printf("\t.ascii \"");
for (s = str; *s != 0; ) {
if (*s++ == '\\') {
(void)esccon(&s);
}
if (s - str > 60) {
fwrite(str, 1, s - str, stdout);
printf("\"\n\t.ascii \"");
str = s;
}
}
fwrite(str, 1, s - str, stdout);
printf("\\0\"\n");
}
static int inbits = 0, inval = 0;
/*
* set 'fsz' bits in sequence to zero.
*/
void
zbits(OFFSZ off, int fsz)
{
int m;
if (idebug)
printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
if ((m = (inbits % SZCHAR))) {
m = SZCHAR - m;
if (fsz < m) {
inbits += fsz;
return;
} else {
fsz -= m;
printf("\t.byte %d\n", inval);
inval = inbits = 0;
}
}
if (fsz >= SZCHAR) {
printf("\t.space %d\n", fsz/SZCHAR);
fsz -= (fsz/SZCHAR) * SZCHAR;
}
if (fsz) {
inval = 0;
inbits = fsz;
}
}
/*
* Initialize a bitfield.
*/
void
infld(CONSZ off, int fsz, CONSZ val)
{
if (idebug)
printf("infld off %lld, fsz %d, val %lld inbits %d\n",
off, fsz, val, inbits);
val &= (1 << fsz)-1;
while (fsz + inbits >= SZCHAR) {
inval |= (val << inbits);
printf("\t.byte %d\n", inval & 255);
fsz -= (SZCHAR - inbits);
val >>= (SZCHAR - inbits);
inval = inbits = 0;
}
if (fsz) {
inval |= (val << inbits);
inbits += fsz;
}
}
/*
* Print an integer constant node, may be associated with a label.
* Do not free the node after use.
* 'off' is bit offset from the beginning of the aggregate
* 'fsz' is the number of bits this is referring to
*/
void
ninval(CONSZ off, int fsz, NODE *p)
{
union { float f; double d; int i[2]; } u;
struct symtab *q;
TWORD t;
int i, j;
t = p->n_type;
if (t > BTMASK)
t = INT; /* pointer */
/*
* The target-independent code does rewrite the NAME nodes
* to ICONS after we prefixed the NAME nodes with ADDROF.
* We do it here. Maybe this is too much of a hack!
*/
if (p->n_op == ADDROF && p->n_left->n_op == NAME) {
p = p->n_left;
p->n_op = ICON;
}
if (p->n_op != ICON && p->n_op != FCON)
cerror("ninval: init node not constant: node %p", p);
if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
uerror("element not constant");
switch (t) {
case LONGLONG:
case ULONGLONG:
i = (p->n_lval >> 32);
j = (p->n_lval & 0xffffffff);
p->n_type = INT;
if (features(FEATURE_BIGENDIAN)) {
p->n_lval = i;
ninval(off+32, 32, p);
p->n_lval = j;
ninval(off, 32, p);
} else {
p->n_lval = j;
ninval(off, 32, p);
p->n_lval = i;
ninval(off+32, 32, p);
}
break;
case INT:
case UNSIGNED:
printf("\t.word 0x%x", (int)p->n_lval);
if ((q = p->n_sp) != NULL) {
if ((q->sclass == STATIC && q->slevel > 0)) {
printf("+" LABFMT, q->soffset);
} else
printf("+%s",
q->soname ? q->soname : exname(q->sname));
}
printf("\n");
break;
case SHORT:
case USHORT:
printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
break;
case BOOL:
if (p->n_lval > 1)
p->n_lval = p->n_lval != 0;
/* FALLTHROUGH */
case CHAR:
case UCHAR:
printf("\t.byte %d\n", (int)p->n_lval & 0xff);
break;
case LDOUBLE:
case DOUBLE:
u.d = (double)p->n_dcon;
#if defined(HOST_BIG_ENDIAN)
if (features(FEATURE_BIGENDIAN))
#else
if (!features(FEATURE_BIGENDIAN))
#endif
printf("\t.word\t0x%x\n\t.word\t0x%x\n",
u.i[0], u.i[1]);
else
printf("\t.word\t0x%x\n\t.word\t0x%x\n",
u.i[1], u.i[0]);
break;
case FLOAT:
u.f = (float)p->n_dcon;
printf("\t.word\t0x%x\n", u.i[0]);
break;
default:
cerror("ninval");
}
}
/*
* Prefix a leading underscore to a global variable (if necessary).
*/
char *
exname(char *p)
{
return (p == NULL ? "" : p);
}
/*
* Map types which are not defined on the local machine.
*/
TWORD
ctype(TWORD type)
{
switch (BTYPE(type)) {
case LONG:
MODTYPE(type,INT);
break;
case ULONG:
MODTYPE(type,UNSIGNED);
break;
}
return (type);
}
/*
* Before calling a function do any tree re-writing for the local machine.
*
* 'p' is the function tree (NAME)
* 'q' is the CM-separated list of arguments.
*/
void
calldec(NODE *p, NODE *q)
{
}
/*
* While handling uninitialised variables, handle variables marked extern.
*/
void
extdec(struct symtab *q)
{
}
/* make a common declaration for id, if reasonable */
void
defzero(struct symtab *sp)
{
int off;
off = tsize(sp->stype, sp->sdf, sp->ssue);
off = (off+(SZCHAR-1))/SZCHAR;
printf(" .%scomm ", sp->sclass == STATIC ? "l" : "");
if (sp->slevel == 0)
printf("%s,0%o\n",
sp->soname ? sp->soname : exname(sp->sname), off);
else
printf(LABFMT ",0%o\n", sp->soffset, off);
}
/*
* va_start(ap, last) implementation.
*
* f is the NAME node for this builtin function.
* a is the argument list containing:
* CM
* ap last
*/
NODE *
arm_builtin_stdarg_start(NODE *f, NODE *a)
{
NODE *p, *q;
int sz = 1;
/* check num args and type */
if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
!ISPTR(a->n_left->n_type))
goto bad;
/* must first deal with argument size; use int size */
p = a->n_right;
if (p->n_type < INT) {
/* round up to word */
sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue);
}
p = buildtree(ADDROF, p, NIL); /* address of last arg */
p = optim(buildtree(PLUS, p, bcon(sz)));
q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
q = buildtree(CAST, q, p);
p = q->n_right;
nfree(q->n_left);
nfree(q);
p = buildtree(ASSIGN, a->n_left, p);
tfree(f);
nfree(a);
return p;
bad:
uerror("bad argument to __builtin_stdarg_start");
return bcon(0);
}
NODE *
arm_builtin_va_arg(NODE *f, NODE *a)
{
NODE *p, *q, *r;
int sz, tmpnr;
/* check num args and type */
if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
!ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
goto bad;
r = a->n_right;
/* get type size */
sz = tsize(r->n_type, r->n_df, r->n_sue) / SZCHAR;
if (sz < SZINT/SZCHAR) {
werror("%s%s promoted to int when passed through ...",
ISUNSIGNED(r->n_type) ? "unsigned " : "",
DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
sz = SZINT/SZCHAR;
}
/* alignment */
p = tcopy(a->n_left);
if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_sue);
}
/* create a copy to a temp node */
q = tempnode(0, p->n_type, p->n_df, p->n_sue);
tmpnr = regno(q);
p = buildtree(ASSIGN, q, p);
q = tempnode(tmpnr, p->n_type, p->n_df,p->n_sue);
q = buildtree(PLUS, q, bcon(sz));
q = buildtree(ASSIGN, a->n_left, q);
q = buildtree(COMOP, p, q);
nfree(a->n_right);
nfree(a);
nfree(f);
p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_sue);
p = buildtree(UMUL, p, NIL);
p = buildtree(COMOP, q, p);
return p;
bad:
uerror("bad argument to __builtin_va_arg");
return bcon(0);
}
NODE *
arm_builtin_va_end(NODE *f, NODE *a)
{
tfree(f);
tfree(a);
return bcon(0);
}
NODE *
arm_builtin_va_copy(NODE *f, NODE *a)
{
if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
goto bad;
tfree(f);
f = buildtree(ASSIGN, a->n_left, a->n_right);
nfree(a);
return f;
bad:
uerror("bad argument to __buildtin_va_copy");
return bcon(0);
}
char *nextsect;
static int constructor;
static int destructor;
/*
* Give target the opportunity of handling pragmas.
*/
int
mypragma(char **ary)
{
if (strcmp(ary[1], "tls") == 0) {
uerror("thread-local storage not supported for this target");
return 1;
}
if (strcmp(ary[1], "constructor") == 0 || strcmp(ary[1], "init") == 0) {
constructor = 1;
return 1;
}
if (strcmp(ary[1], "destructor") == 0 || strcmp(ary[1], "fini") == 0) {
destructor = 1;
return 1;
}
if (strcmp(ary[1], "section") || ary[2] == NULL)
return 0;
nextsect = newstring(ary[2], strlen(ary[2]));
return 1;
}
/*
* Called when a identifier has been declared, to give target last word.
*/
void
fixdef(struct symtab *sp)
{
if ((constructor || destructor) && (sp->sclass != PARAM)) {
printf("\t.section .%ctors,\"aw\",@progbits\n",
constructor ? 'c' : 'd');
printf("\t.p2align 2\n");
printf("\t.long %s\n", exname(sp->sname));
printf("\t.previous\n");
constructor = destructor = 0;
}
}
void
pass1_lastchance(struct interpass *ip)
{
}
File diff suppressed because it is too large Load Diff
+263
View File
@@ -0,0 +1,263 @@
/* $Id: macdefs.h,v 1.12 2009/01/24 21:43:48 gmcgarry Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Machine-dependent defines for both passes.
*/
/*
* Convert (multi-)character constant to integer.
*/
#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24);
/*
* Storage space requirements
*/
#define SZCHAR 8
#define SZBOOL 32
#define SZINT 32
#define SZFLOAT 32
#define SZDOUBLE 64
#define SZLDOUBLE 64
#define SZLONG 32
#define SZSHORT 16
#define SZLONGLONG 64
#define SZPOINT(t) 32
/*
* Alignment constraints
*/
#define ALCHAR 8
#define ALBOOL 32
#define ALINT 32
#define ALFLOAT 32
#define ALDOUBLE 32
#define ALLDOUBLE 32
#define ALLONG 32
#define ALLONGLONG 32
#define ALSHORT 16
#define ALPOINT 32
#define ALSTRUCT 32
#define ALSTACK 32
/*
* Min/max values.
*/
#define MIN_CHAR -128
#define MAX_CHAR 127
#define MAX_UCHAR 255
#define MIN_SHORT -32768
#define MAX_SHORT 32767
#define MAX_USHORT 65535
#define MIN_INT -1
#define MAX_INT 0x7fffffff
#define MAX_UNSIGNED 0xffffffff
#define MIN_LONG MIN_INT
#define MAX_LONG MAX_INT
#define MAX_ULONG MAX_UNSIGNED
#define MIN_LONGLONG 0x8000000000000000LL
#define MAX_LONGLONG 0x7fffffffffffffffLL
#define MAX_ULONGLONG 0xffffffffffffffffULL
#define BOOL_TYPE INT /* what used to store _Bool */
/*
* Use large-enough types.
*/
typedef long long CONSZ;
typedef unsigned long long U_CONSZ;
typedef long long OFFSZ;
#define CONFMT "#%lld" /* format for printing constants */
#define LABFMT ".L%d" /* format for printing labels */
#define STABLBL "LL%d" /* format for stab (debugging) labels */
#define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */
#undef FIELDOPS /* no bit-field instructions */
#define ENUMSIZE(high,low) INT /* enums are always stored in full int */
/* Definitions mostly used in pass2 */
#define BYTEOFF(x) ((x)&03)
#define wdal(k) (BYTEOFF(k)==0)
#define BITOOR(x) (x) /* bit offset to oreg offset XXX die! */
#define STOARG(p)
#define STOFARG(p)
#define STOSTARG(p)
#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \
(t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
#define R0 0
#define R1 1
#define R2 2
#define R3 3
#define R4 4
#define R5 5
#define R6 6
#define R7 7
#define R8 8
#define R9 9
#define R10 10
#define R11 11
#define R12 12
#define R13 13
#define R14 14
#define R15 15
#define SL R10
#define FP R11
#define IP R12
#define SP R13
#define LR R14
#define PC R15
#define R0R1 16
#define R1R2 17
#define R2R3 18
#define R3R4 19
#define R4R5 20
#define R5R6 21
#define R6R7 22
#define R7R8 23
#define R8R9 24
#define R9R10 25
#define F0 26
#define F1 27
#define F2 28
#define F3 29
#define F4 30
#define F5 31
#define F6 32
#define F7 33
#define NUMCLASS 3
#define MAXREGS 34
#define RSTATUS \
SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
0, 0, 0, 0, 0, \
SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG, \
SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
SCREG, SCREG, SCREG, SCREG, \
SCREG, SCREG, SCREG, SCREG, \
#define ROVERLAP \
{ R0R1, -1 }, \
{ R0R1, R1R2, -1 }, \
{ R1R2, R2R3, -1 }, \
{ R2R3, R3R4, -1 }, \
{ R3R4, R4R5, -1 }, \
{ R4R5, R5R6, -1 }, \
{ R5R6, R6R7, -1 }, \
{ R6R7, R7R8, -1 }, \
{ R7R8, R8R9, -1 }, \
{ R8R9, R9R10, -1 }, \
{ R9R10, -1 }, \
{ -1 }, \
{ -1 }, \
{ -1 }, \
{ -1 }, \
{ -1 }, \
{ R0, R1, R1R2, -1 }, \
{ R1, R2, R0R1, R2R3, -1 }, \
{ R2, R3, R1R2, R3R4, -1 }, \
{ R3, R4, R2R3, R4R5, -1 }, \
{ R4, R5, R3R4, R5R6, -1 }, \
{ R5, R6, R4R5, R6R7, -1 }, \
{ R6, R7, R5R6, R7R8, -1 }, \
{ R7, R8, R6R7, R8R9, -1 }, \
{ R8, R9, R7R8, R9R10, -1 }, \
{ R9, R10, R8R9, -1 }, \
{ -1, }, \
{ -1, }, \
{ -1, }, \
{ -1, }, \
{ -1, }, \
{ -1, }, \
{ -1, }, \
{ -1, }, \
#define BACKTEMP /* stack grows negatively for temporaries */
#define BACKAUTO /* stack grows negatively for automatics */
#define ARGINIT (4*8) /* # bits above fp where arguments start */
#define AUTOINIT (12*8) /* # bits above fp where automatics start */
#undef FIELDOPS /* no bit-field instructions */
#define RTOLBYTES 1 /* bytes are numbered right to left */
/* XXX - to die */
#define FPREG FP /* frame pointer */
/* Return a register class based on the type of the node */
#define PCLASS(p) (1 << gclass((p)->n_type))
#define GCLASS(x) (x < 16 ? CLASSA : x < 26 ? CLASSB : CLASSC)
#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */
#define ENCRD(x) (x) /* Encode dest reg in n_reg */
#define ENCRA1(x) ((x) << 6) /* A1 */
#define ENCRA2(x) ((x) << 12) /* A2 */
#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */
#define RETREG(x) retreg(x)
int COLORMAP(int c, int *r);
int retreg(int ty);
int features(int f);
#define FEATURE_BIGENDIAN 0x00010000
#define FEATURE_HALFWORDS 0x00020000 /* ldrsh/ldrh, ldrsb */
#define FEATURE_EXTEND 0x00040000 /* sxth, sxtb, uxth, uxtb */
#define FEATURE_MUL 0x00080000
#define FEATURE_MULL 0x00100000
#define FEATURE_FPA 0x10000000
#define FEATURE_VFP 0x20000000
#define FEATURE_HARDFLOAT (FEATURE_FPA|FEATURE_VFP)
#define TARGET_STDARGS
#define TARGET_BUILTINS \
{ "__builtin_stdarg_start", arm_builtin_stdarg_start }, \
{ "__builtin_va_arg", arm_builtin_va_arg }, \
{ "__builtin_va_end", arm_builtin_va_end }, \
{ "__builtin_va_copy", arm_builtin_va_copy },
#define NODE struct node
struct node;
NODE *arm_builtin_stdarg_start(NODE *f, NODE *a);
NODE *arm_builtin_va_arg(NODE *f, NODE *a);
NODE *arm_builtin_va_end(NODE *f, NODE *a);
NODE *arm_builtin_va_copy(NODE *f, NODE *a);
#undef NODE
#define COM "\t@ "
#define NARGREGS 4
+339
View File
@@ -0,0 +1,339 @@
/* $Id: order.c,v 1.9 2008/09/27 07:35:22 ragge Exp $ */
/*
* Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Machine-dependent code-generation strategy (pass 2).
*/
#include <assert.h>
#include <string.h>
#include "pass2.h"
/*
* Check size of offset in OREG. Called by oregok() to see if an
* OREG can be generated.
*/
int
notoff(TWORD ty, int r, CONSZ off, char *cp)
{
if (cp && cp[0]) return 1;
if (DEUNSIGN(ty) == INT || ty == UCHAR)
return !(off < 4096 && off > -4096);
else
return !(off < 256 && off > -256);
}
/*
* Generate instructions for an OREG. Why is this routine MD?
* Called by swmatch().
*/
void
offstar(NODE *p, int shape)
{
NODE *r;
if (isreg(p))
return; /* Is already OREG */
r = p->n_right;
if( p->n_op == PLUS || p->n_op == MINUS ){
if( r->n_op == ICON ){
if (isreg(p->n_left) == 0)
(void)geninsn(p->n_left, INAREG);
/* Converted in ormake() */
return;
}
/* usually for arraying indexing: */
if (r->n_op == LS && r->n_right->n_op == ICON &&
r->n_right->n_lval == 2 && p->n_op == PLUS) {
if (isreg(p->n_left) == 0)
(void)geninsn(p->n_left, INAREG);
if (isreg(r->n_left) == 0)
(void)geninsn(r->n_left, INAREG);
return;
}
}
(void)geninsn(p, INAREG);
}
/*
* Unable to convert to OREG (notoff() returned failure). Output
* suitable instructions to replace OREG.
*/
void
myormake(NODE *q)
{
NODE *p, *r;
if (x2debug)
printf("myormake(%p)\n", q);
p = q->n_left;
/*
* This handles failed OREGs conversions, due to the offset
* being too large for an OREG.
*/
if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) {
if (isreg(p->n_left) == 0)
(void)geninsn(p->n_left, INAREG);
if (isreg(p->n_right) == 0)
(void)geninsn(p->n_right, INAREG);
(void)geninsn(p, INAREG);
} else if (p->n_op == REG) {
q->n_op = OREG;
q->n_lval = p->n_lval;
q->n_rval = p->n_rval;
tfree(p);
} else if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
r->n_right->n_op == ICON && r->n_right->n_lval == 2 &&
p->n_left->n_op == REG && r->n_left->n_op == REG) {
q->n_op = OREG;
q->n_lval = 0;
q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval,
r->n_right->n_lval);
tfree(p);
}
}
/*
* Check to if the UMUL node can be converted into an OREG.
*/
int
shumul(NODE *p, int shape)
{
/* Turns currently anything into OREG */
if (shape & SOREG)
return SROREG;
return SRNOPE;
}
/*
* Rewrite operations on binary operators (like +, -, etc...).
* Called as a result of a failed table lookup.
*
* Return nonzero to retry table search on new tree, or zero to fail.
*/
int
setbin(NODE *p)
{
return 0;
}
/*
* Rewrite assignment operations.
* Called as a result of a failed table lookup.
*
* Return nonzero to retry table search on new tree, or zero to fail.
*/
int
setasg(NODE *p, int cookie)
{
return 0;
}
/*
* Rewrite UMUL operation.
* Called as a result of a failed table lookup.
*
* Return nonzero to retry table search on new tree, or zero to fail.
*/
int
setuni(NODE *p, int cookie)
{
return 0;
}
/*
* Special handling of some instruction register allocation.
*
* Called as a result of specifying NSPECIAL in the table.
*/
struct rspecial *
nspecial(struct optab *q)
{
switch (q->op) {
#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP)
case UMINUS:
case SCONV:
if (q->lshape == SBREG && q->rshape == SAREG) {
static struct rspecial s[] = {
{ NLEFT, R0R1 },
{ NRES, R0 },
{ 0 }
};
return s;
} else if (q->lshape == SAREG && q->rshape == SBREG) {
static struct rspecial s[] = {
{ NLEFT, R0 },
{ NRES, R0R1 },
{ 0 }
};
return s;
} else if (q->lshape == SAREG && q->rshape == SAREG) {
static struct rspecial s[] = {
{ NLEFT, R0 },
{ NRES, R0 },
{ 0 }
};
return s;
} else if (q->lshape == SBREG && q->rshape == SBREG) {
static struct rspecial s[] = {
{ NLEFT, R0R1 },
{ NRES, R0R1 },
{ 0 }
};
return s;
}
case OPLOG:
if (q->lshape == SBREG) {
static struct rspecial s[] = {
{ NLEFT, R0R1 },
{ NRIGHT, R2R3 },
{ NRES, R0 },
{ 0 }
};
return s;
} else if (q->lshape == SAREG) {
static struct rspecial s[] = {
{ NLEFT, R0 },
{ NRIGHT, R1 },
{ NRES, R0 },
{ 0 }
};
return s;
}
case PLUS:
case MINUS:
case MUL:
#endif
case MOD:
case DIV:
if (q->lshape == SBREG) {
static struct rspecial s[] = {
{ NLEFT, R0R1 },
{ NRIGHT, R2R3 },
{ NRES, R0R1 },
{ 0 }
};
return s;
} else if (q->lshape == SAREG) {
static struct rspecial s[] = {
{ NLEFT, R0 },
{ NRIGHT, R1 },
{ NRES, R0 },
{ 0 }
};
return s;
}
case LS:
case RS:
if (q->lshape == SBREG) {
static struct rspecial s[] = {
{ NLEFT, R0R1 },
{ NRIGHT, R2 },
{ NRES, R0R1 },
{ 0 }
};
return s;
} else if (q->lshape == SAREG) {
static struct rspecial s[] = {
{ NLEFT, R0 },
{ NRIGHT, R1 },
{ NRES, R0 },
{ 0 }
};
return s;
}
case STASG:
{
static struct rspecial s[] = {
{ NEVER, R0 },
{ NRIGHT, R1 },
{ NEVER, R2 },
{ 0 } };
return s;
}
break;
default:
break;
}
#ifdef PCC_DEBUG
comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring);
#endif
return 0; /* XXX gcc */
}
/*
* Set evaluation order of a binary node ('+','-', '*', '/', etc) if it
* differs from default.
*/
int
setorder(NODE *p)
{
return 0;
}
/*
* Set registers "live" at function calls (like arguments in registers).
* This is for liveness analysis of registers.
*/
int *
livecall(NODE *p)
{
static int r[] = { R3, R2, R1, R0, -1 };
int num = 1;
if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
return &r[4-0];
for (p = p->n_right; p->n_op == CM; p = p->n_left)
num += szty(p->n_right->n_type);
num += szty(p->n_right->n_type);
num = (num > 4 ? 4 : num);
return &r[4 - num];
}
/*
* Signal whether the instruction is acceptable for this target.
*/
int
acceptable(struct optab *op)
{
return features(op->visit & 0xffff0000);
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
* Fix floating-point arguments in registers
* Fix structure arguments in registers
+726
View File
@@ -0,0 +1,726 @@
/* $Id: code.c,v 1.17 2010/09/19 14:01:35 ragge Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
* Simon Olsson (simols-1@student.ltu.se) 2005.
*/
#include <assert.h>
#include "pass1.h"
/*
* Define everything needed to print out some data (or text).
* This means segment, alignment, visibility, etc.
*/
void
defloc(struct symtab *sp)
{
static char *loctbl[] = { "text", "data", "section .rodata" };
static int lastloc = -1;
TWORD t;
char *n;
int s;
if (sp == NULL) {
lastloc = -1;
return;
}
t = sp->stype;
s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
lastloc = s;
if (s == PROG)
return; /* text is written in prologue() */
if (s != lastloc)
printf(" .%s\n", loctbl[s]);
printf(" .p2align %d\n", ispow2(talign(t, sp->sap)));
n = sp->soname ? sp->soname : sp->sname;
if (sp->sclass == EXTDEF)
printf(" .globl %s\n", n);
if (sp->slevel == 0) {
#ifdef USE_GAS
printf("\t.type %s,@object\n", n);
printf("\t.size %s," CONFMT "\n", n,
tsize(sp->stype, sp->sdf, sp->sap));
#endif
printf("%s:\n", n);
} else
printf(LABFMT ":\n", sp->soffset);
}
#ifdef notdef
/*
* cause the alignment to become a multiple of n
* never called for text segment.
*/
void
defalign(int n)
{
n = ispow2(n / SZCHAR);
if (n == -1)
cerror("defalign: n != 2^i");
printf("\t.p2align %d\n", n);
}
/*
* define the current location as the name p->sname
* never called for text segment.
*/
void
defnam(struct symtab *p)
{
char *c = p->soname;
if (p->sclass == EXTDEF)
printf("\t.globl %s\n", c);
#ifdef USE_GAS
printf("\t.type %s,@object\n", c);
printf("\t.size %s," CONFMT "\n", c, tsize(p->stype, p->sdf, p->sap));
#endif
printf("%s:\n", c);
}
#endif
static int rvnr;
/*
* code for the end of a function
* deals with struct return here
*/
void
efcode()
{
NODE *p, *q;
int tempnr;
int ty;
if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
return;
ty = cftnsp->stype - FTN;
q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
q->n_rval = V0;
p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
tempnr = regno(p);
p = buildtree(ASSIGN, p, q);
ecomp(p);
q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
q = buildtree(UMUL, q, NIL);
p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
p = buildtree(UMUL, p, NIL);
p = buildtree(ASSIGN, p, q);
ecomp(p);
q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
p->n_rval = V0;
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
/* Put a symbol in a temporary
* used by bfcode() and its helpers */
static void
putintemp(struct symtab *sym)
{
NODE *p;
p = tempnode(0, sym->stype, sym->sdf, sym->sap);
p = buildtree(ASSIGN, p, nametree(sym));
sym->soffset = regno(p->n_left);
sym->sflags |= STNODE;
ecomp(p);
}
/* setup the hidden pointer to struct return parameter
* used by bfcode() */
static void
param_retptr(void)
{
NODE *p, *q;
p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
rvnr = regno(p);
q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
q->n_rval = A0;
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
/* setup struct parameter
* push the registers out to memory
* used by bfcode() */
static void
param_struct(struct symtab *sym, int *regp)
{
int reg = *regp;
NODE *p, *q;
int navail;
int sz;
int off;
int num;
int i;
navail = nargregs - (reg - A0);
sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
off = ARGINIT/SZINT + (reg - A0);
num = sz > navail ? navail : sz;
for (i = 0; i < num; i++) {
q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
q->n_rval = reg++;
p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
p->n_rval = FP;
p = block(PLUS, p, bcon(4*off++), INT, 0, MKAP(INT));
p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
*regp = reg;
}
/* setup a 64-bit parameter (double/ldouble/longlong)
* used by bfcode() */
static void
param_64bit(struct symtab *sym, int *regp, int dotemps)
{
int reg = *regp;
NODE *p, *q;
int navail;
/* alignment */
++reg;
reg &= ~1;
navail = nargregs - (reg - A0);
if (navail < 2) {
/* would have appeared half in registers/half
* on the stack, but alignment ensures it
* appears on the stack */
if (dotemps)
putintemp(sym);
*regp = reg;
return;
}
q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
q->n_rval = A0A1 + (reg - A0);
if (dotemps) {
p = tempnode(0, sym->stype, sym->sdf, sym->sap);
sym->soffset = regno(p);
sym->sflags |= STNODE;
} else {
p = nametree(sym);
}
p = buildtree(ASSIGN, p, q);
ecomp(p);
*regp = reg + 2;
}
/* setup a 32-bit param on the stack
* used by bfcode() */
static void
param_32bit(struct symtab *sym, int *regp, int dotemps)
{
NODE *p, *q;
q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
q->n_rval = (*regp)++;
if (dotemps) {
p = tempnode(0, sym->stype, sym->sdf, sym->sap);
sym->soffset = regno(p);
sym->sflags |= STNODE;
} else {
p = nametree(sym);
}
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
/*
* XXX This is a hack. We cannot have (l)doubles in more than one
* register class. So we bounce them in and out of temps to
* move them in and out of the right registers.
*/
static void
param_double(struct symtab *sym, int *regp, int dotemps)
{
int reg = *regp;
NODE *p, *q, *t;
int navail;
int tmpnr;
/* alignment */
++reg;
reg &= ~1;
navail = nargregs - (reg - A0);
if (navail < 2) {
/* would have appeared half in registers/half
* on the stack, but alignment ensures it
* appears on the stack */
if (dotemps)
putintemp(sym);
*regp = reg;
return;
}
t = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
tmpnr = regno(t);
q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
q->n_rval = A0A1 + (reg - A0);
p = buildtree(ASSIGN, t, q);
ecomp(p);
if (dotemps) {
sym->soffset = tmpnr;
sym->sflags |= STNODE;
} else {
q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
p = nametree(sym);
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
*regp = reg + 2;
}
/*
* XXX This is a hack. We cannot have floats in more than one
* register class. So we bounce them in and out of temps to
* move them in and out of the right registers.
*/
static void
param_float(struct symtab *sym, int *regp, int dotemps)
{
NODE *p, *q, *t;
int tmpnr;
t = tempnode(0, INT, 0, MKAP(INT));
tmpnr = regno(t);
q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
q->n_rval = (*regp)++;
p = buildtree(ASSIGN, t, q);
ecomp(p);
if (dotemps) {
sym->soffset = tmpnr;
sym->sflags |= STNODE;
} else {
q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
p = nametree(sym);
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
}
/*
* code for the beginning of a function; a is an array of
* indices in symtab for the arguments; n is the number
*/
void
bfcode(struct symtab **sp, int cnt)
{
union arglist *usym;
int lastreg = A0 + nargregs - 1;
int saveallargs = 0;
int i, reg;
/*
* Detect if this function has ellipses and save all
* argument register onto stack.
*/
usym = cftnsp->sdf->dfun;
while (usym && usym->type != TNULL) {
if (usym->type == TELLIPSIS) {
saveallargs = 1;
break;
}
++usym;
}
reg = A0;
/* assign hidden return structure to temporary */
if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
param_retptr();
++reg;
}
/* recalculate the arg offset and create TEMP moves */
for (i = 0; i < cnt; i++) {
if ((reg > lastreg) && !xtemps)
break;
else if (reg > lastreg)
putintemp(sp[i]);
else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
param_struct(sp[i], &reg);
else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
param_64bit(sp[i], &reg, xtemps && !saveallargs);
else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
param_double(sp[i], &reg, xtemps && !saveallargs);
else if (sp[i]->stype == FLOAT)
param_float(sp[i], &reg, xtemps && !saveallargs);
else
param_32bit(sp[i], &reg, xtemps && !saveallargs);
}
/* if saveallargs, save the rest of the args onto the stack */
if (!saveallargs)
return;
while (reg <= lastreg) {
NODE *p, *q;
int off = ARGINIT/SZINT + (reg - A0);
q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
q->n_rval = reg++;
p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
p->n_rval = FP;
p = block(PLUS, p, bcon(4*off), INT, 0, MKAP(INT));
p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
p = buildtree(ASSIGN, p, q);
ecomp(p);
}
}
/*
* by now, the automatics and register variables are allocated
*/
void
bccode()
{
SETOFF(autooff, SZINT);
}
/* called just before final exit */
/* flag is 1 if errors, 0 if none */
void
ejobcode(int flag )
{
}
void
bjobcode()
{
printf("\t.section .mdebug.abi32\n");
printf("\t.previous\n");
printf("\t.abicalls\n");
}
#ifdef notdef
/*
* Print character t at position i in one string, until t == -1.
* Locctr & label is already defined.
*/
void
bycode(int t, int i)
{
static int lastoctal = 0;
/* put byte i+1 in a string */
if (t < 0) {
if (i != 0)
puts("\\000\"");
} else {
if (i == 0)
printf("\t.ascii \"");
if (t == 0)
return;
else if (t == '\\' || t == '"') {
lastoctal = 0;
putchar('\\');
putchar(t);
} else if (t == 011) {
printf("\\t");
} else if (t == 012) {
printf("\\n");
} else if (t < 040 || t >= 0177) {
lastoctal++;
printf("\\%o",t);
} else if (lastoctal && '0' <= t && t <= '9') {
lastoctal = 0;
printf("\"\n\t.ascii \"%c", t);
} else {
lastoctal = 0;
putchar(t);
}
}
}
#endif
/*
* return the alignment of field of type t
*/
int
fldal(unsigned int t)
{
uerror("illegal field type");
return(ALINT);
}
/* fix up type of field p */
void
fldty(struct symtab *p)
{
}
/*
* XXX - fix genswitch.
*/
int
mygenswitch(int num, TWORD type, struct swents **p, int n)
{
return 0;
}
/* setup call stack with a structure */
/* called from moveargs() */
static NODE *
movearg_struct(NODE *p, NODE *parent, int *regp)
{
int reg = *regp;
NODE *l, *q, *t, *r;
int tmpnr;
int navail;
int off;
int num;
int sz;
int ty;
int i;
navail = nargregs - (reg - A0);
sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
num = sz > navail ? navail : sz;
l = p->n_left;
nfree(p);
ty = l->n_type;
t = tempnode(0, l->n_type, l->n_df, l->n_ap);
tmpnr = regno(t);
l = buildtree(ASSIGN, t, l);
if (p != parent) {
q = parent->n_left;
} else
q = NULL;
/* copy structure into registers */
for (i = 0; i < num; i++) {
t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
t = buildtree(UMUL, t, NIL);
r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
r->n_rval = reg++;
r = buildtree(ASSIGN, r, t);
if (q == NULL)
q = r;
else
q = block(CM, q, r, INT, 0, MKAP(INT));
}
off = ARGINIT/SZINT + nargregs;
for (i = num; i < sz; i++) {
t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
t = buildtree(UMUL, t, NIL);
r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
r->n_rval = FP;
r = block(PLUS, r, bcon(4*off++), INT, 0, MKAP(INT));
r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
r = buildtree(ASSIGN, r, t);
if (q == NULL)
q = r;
else
q = block(CM, q, r, INT, 0, MKAP(INT));
}
if (parent->n_op == CM) {
parent->n_left = q;
q = l;
} else {
q = block(CM, q, l, INT, 0, MKAP(INT));
}
*regp = reg;
return q;
}
/* setup call stack with 64-bit argument */
/* called from moveargs() */
static NODE *
movearg_64bit(NODE *p, int *regp)
{
int reg = *regp;
NODE *q;
int lastarg;
/* alignment */
++reg;
reg &= ~1;
lastarg = A0 + nargregs - 1;
if (reg > lastarg) {
*regp = reg;
return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap);
}
q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
q->n_rval = A0A1 + (reg - A0);
q = buildtree(ASSIGN, q, p);
*regp = reg + 2;
return q;
}
/* setup call stack with 32-bit argument */
/* called from moveargs() */
static NODE *
movearg_32bit(NODE *p, int *regp)
{
int reg = *regp;
NODE *q;
q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
q->n_rval = reg++;
q = buildtree(ASSIGN, q, p);
*regp = reg;
return q;
}
static NODE *
moveargs(NODE *p, int *regp)
{
NODE *r, **rp;
int lastreg;
int reg;
if (p->n_op == CM) {
p->n_left = moveargs(p->n_left, regp);
r = p->n_right;
rp = &p->n_right;
} else {
r = p;
rp = &p;
}
lastreg = A0 + nargregs - 1;
reg = *regp;
if (reg > lastreg && r->n_op != STARG)
*rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
else if (r->n_op == STARG) {
*rp = movearg_struct(r, p, regp);
} else if (DEUNSIGN(r->n_type) == LONGLONG) {
*rp = movearg_64bit(r, regp);
} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
/* XXX bounce in and out of temporary to change to longlong */
NODE *t1 = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
int tmpnr = regno(t1);
NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
t1 = movearg_64bit(t1, regp);
r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
if (p->n_op == CM) {
p->n_left = buildtree(CM, p->n_left, t1);
p->n_right = r;
} else {
p = buildtree(CM, t1, r);
}
} else if (r->n_type == FLOAT) {
/* XXX bounce in and out of temporary to change to int */
NODE *t1 = tempnode(0, INT, 0, MKAP(INT));
int tmpnr = regno(t1);
NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
t1 = movearg_32bit(t1, regp);
r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
if (p->n_op == CM) {
p->n_left = buildtree(CM, p->n_left, t1);
p->n_right = r;
} else {
p = buildtree(CM, t1, r);
}
} else {
*rp = movearg_32bit(r, regp);
}
return p;
}
/*
* Called with a function call with arguments as argument.
* This is done early in buildtree() and only done once.
*/
NODE *
funcode(NODE *p)
{
int regnum = A0;
NODE *l, *r, *t, *q;
int ty;
l = p->n_left;
r = p->n_right;
/*
* if returning a structure, make the first argument
* a hidden pointer to return structure.
*/
ty = DECREF(l->n_type);
if (ty == STRTY+FTN || ty == UNIONTY+FTN) {
ty = DECREF(l->n_type) - FTN;
q = tempnode(0, ty, l->n_df, l->n_ap);
q = buildtree(ADDROF, q, NIL);
if (r->n_op != CM) {
p->n_right = block(CM, q, r, INCREF(ty),
l->n_df, l->n_ap);
} else {
for (t = r; t->n_left->n_op == CM; t = t->n_left)
;
t->n_left = block(CM, q, t->n_left, INCREF(ty),
l->n_df, l->n_ap);
}
}
p->n_right = moveargs(p->n_right, &regnum);
return p;
}
+925
View File
@@ -0,0 +1,925 @@
/* $Id: local.c,v 1.23 2010/09/19 14:05:58 ragge Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
* Simon Olsson (simols-1@student.ltu.se) 2005.
*/
#include <assert.h>
#include "pass1.h"
#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
static int inbits, inval;
/* this is called to do local transformations on
* an expression tree preparitory to its being
* written out in intermediate code.
*/
NODE *
clocal(NODE *p)
{
struct symtab *q;
NODE *r, *l;
int o;
int m;
TWORD ty;
int tmpnr, isptrvoid = 0;
#ifdef PCC_DEBUG
if (xdebug) {
printf("clocal in: %p\n", p);
fwalk(p, eprint, 0);
}
#endif
switch (o = p->n_op) {
case UCALL:
case CALL:
case STCALL:
case USTCALL:
if (p->n_type == VOID)
break;
/*
* if the function returns void*, ecode() invokes
* delvoid() to convert it to uchar*.
* We just let this happen on the ASSIGN to the temp,
* and cast the pointer back to void* on access
* from the temp.
*/
if (p->n_type == PTR+VOID)
isptrvoid = 1;
r = tempnode(0, p->n_type, p->n_df, p->n_ap);
tmpnr = regno(r);
r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
if (isptrvoid) {
p = block(PCONV, p, NIL, PTR+VOID,
p->n_df, MKAP(PTR+VOID));
}
p = buildtree(COMOP, r, p);
break;
case NAME:
if ((q = p->n_sp) == NULL)
return p; /* Nothing to care about */
switch (q->sclass) {
case PARAM:
case AUTO:
/* fake up a structure reference */
r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
r->n_lval = 0;
r->n_rval = FP;
p = stref(block(STREF, r, p, 0, 0, 0));
break;
case STATIC:
if (q->slevel == 0)
break;
p->n_lval = 0;
p->n_sp = q;
break;
case REGISTER:
p->n_op = REG;
p->n_lval = 0;
p->n_rval = q->soffset;
break;
}
break;
case FUNARG:
/* Args smaller than int are given as int */
if (p->n_type != CHAR && p->n_type != UCHAR &&
p->n_type != SHORT && p->n_type != USHORT)
break;
p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKAP(INT));
p->n_type = INT;
p->n_ap = MKAP(INT);
p->n_rval = SZINT;
break;
case CBRANCH:
l = p->n_left;
/*
* Remove unnecessary conversion ops.
*/
if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
if (coptype(l->n_op) != BITYPE)
break;
if (l->n_right->n_op == ICON) {
r = l->n_left->n_left;
if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
break;
/* Type must be correct */
ty = r->n_type;
nfree(l->n_left);
l->n_left = r;
l->n_type = ty;
l->n_right->n_type = ty;
}
#if 0
else if (l->n_right->n_op == SCONV &&
l->n_left->n_type == l->n_right->n_type) {
r = l->n_left->n_left;
nfree(l->n_left);
l->n_left = r;
r = l->n_right->n_left;
nfree(l->n_right);
l->n_right = r;
}
#endif
}
break;
case PCONV:
/* Remove redundant PCONV's. Be careful */
l = p->n_left;
if (l->n_op == ICON) {
l->n_lval = (unsigned)l->n_lval;
goto delp;
}
if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
/* float etc? */
p->n_left = block(SCONV, l, NIL,
UNSIGNED, 0, MKAP(UNSIGNED));
break;
}
/* if left is SCONV, cannot remove */
if (l->n_op == SCONV)
break;
/* avoid ADDROF TEMP */
if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
break;
/* if conversion to another pointer type, just remove */
if (p->n_type > BTMASK && l->n_type > BTMASK)
goto delp;
break;
delp: l->n_type = p->n_type;
l->n_qual = p->n_qual;
l->n_df = p->n_df;
l->n_ap = p->n_ap;
nfree(p);
p = l;
break;
case SCONV:
l = p->n_left;
if (p->n_type == l->n_type) {
nfree(p);
p = l;
break;
}
if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
btattr[p->n_type].atypsz == btattr[l->n_type].atypsz) {
if (p->n_type != FLOAT && p->n_type != DOUBLE &&
l->n_type != FLOAT && l->n_type != DOUBLE &&
l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
if (l->n_op == NAME || l->n_op == UMUL ||
l->n_op == TEMP) {
l->n_type = p->n_type;
nfree(p);
p = l;
break;
}
}
}
if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
coptype(l->n_op) == BITYPE) {
l->n_type = p->n_type;
nfree(p);
p = l;
}
if (DEUNSIGN(p->n_type) == SHORT &&
DEUNSIGN(l->n_type) == SHORT) {
nfree(p);
p = l;
}
/* convert float/double to int before to (u)char/(u)short */
if ((DEUNSIGN(p->n_type) == CHAR ||
DEUNSIGN(p->n_type) == SHORT) &&
(l->n_type == FLOAT || l->n_type == DOUBLE ||
l->n_type == LDOUBLE)) {
p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
p->n_left->n_type = INT;
break;
}
/* convert (u)char/(u)short to int before float/double */
if ((p->n_type == FLOAT || p->n_type == DOUBLE ||
p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
DEUNSIGN(l->n_type) == SHORT)) {
p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
p->n_left->n_type = INT;
break;
}
o = l->n_op;
m = p->n_type;
if (o == ICON) {
CONSZ val = l->n_lval;
if (!ISPTR(m)) /* Pointers don't need to be conv'd */
switch (m) {
case BOOL:
l->n_lval = l->n_lval != 0;
break;
case CHAR:
l->n_lval = (char)val;
break;
case UCHAR:
l->n_lval = val & 0377;
break;
case SHORT:
l->n_lval = (short)val;
break;
case USHORT:
l->n_lval = val & 0177777;
break;
case ULONG:
case UNSIGNED:
l->n_lval = val & 0xffffffff;
break;
case LONG:
case INT:
l->n_lval = (int)val;
break;
case LONGLONG:
l->n_lval = (long long)val;
break;
case ULONGLONG:
l->n_lval = val;
break;
case VOID:
break;
case LDOUBLE:
case DOUBLE:
case FLOAT:
l->n_op = FCON;
l->n_dcon = val;
break;
default:
cerror("unknown type %d", m);
}
l->n_type = m;
nfree(p);
p = l;
} else if (o == FCON) {
l->n_lval = l->n_dcon;
l->n_sp = NULL;
l->n_op = ICON;
l->n_type = m;
l->n_ap = MKAP(m);
nfree(p);
p = clocal(l);
}
break;
case MOD:
case DIV:
if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
break;
if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
break;
/* make it an int division by inserting conversions */
p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKAP(INT));
p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKAP(INT));
p = block(SCONV, p, NIL, p->n_type, 0, MKAP(p->n_type));
p->n_left->n_type = INT;
break;
case PMCONV:
case PVCONV:
if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
nfree(p);
p = buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right);
break;
case FORCE:
/* put return value in return reg */
p->n_op = ASSIGN;
p->n_right = p->n_left;
p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
p->n_left->n_rval = RETREG(p->n_type);
break;
}
#ifdef PCC_DEBUG
if (xdebug) {
printf("clocal out: %p\n", p);
fwalk(p, eprint, 0);
}
#endif
return(p);
}
void
myp2tree(NODE *p)
{
struct symtab *sp;
if (p->n_op != FCON)
return;
/* Write float constants to memory */
sp = IALLOC(sizeof(struct symtab));
sp->sclass = STATIC;
sp->sap = MKAP(p->n_type);
sp->slevel = 1; /* fake numeric label */
sp->soffset = getlab();
sp->sflags = 0;
sp->stype = p->n_type;
sp->squal = (CON >> TSHIFT);
defloc(sp);
ninval(0, sp->sap->atypsz, p);
p->n_op = NAME;
p->n_lval = 0;
p->n_sp = sp;
}
/*ARGSUSED*/
int
andable(NODE *p)
{
return(1); /* all names can have & taken on them */
}
/*
* at the end of the arguments of a ftn, set the automatic offset
*/
void
cendarg()
{
autooff = AUTOINIT;
}
/*
* is an automatic variable of type t OK for a register variable
*/
int
cisreg(TWORD t)
{
if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
return(1);
return 0; /* XXX - fix reg assignment in pftn.c */
}
/*
* return a node, for structure references, which is suitable for
* being added to a pointer of type t, in order to be off bits offset
* into a structure
* t, d, and s are the type, dimension offset, and sizeoffset
* Be careful about only handling first-level pointers, the following
* indirections must be fullword.
*/
NODE *
offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *sue)
{
NODE *p;
if (xdebug)
printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
off, t, d, 0);
p = bcon(off/SZCHAR);
return p;
}
/*
* Allocate off bits on the stack. p is a tree that when evaluated
* is the multiply count for off, t is a NAME node where to write
* the allocated address.
*/
void
spalloc(NODE *t, NODE *p, OFFSZ off)
{
NODE *sp;
int nbytes = off / SZCHAR;
p = buildtree(MUL, p, bcon(nbytes));
p = buildtree(PLUS, p, bcon(7));
p = buildtree(AND, p, bcon(~7));
/* subtract the size from sp */
sp = block(REG, NIL, NIL, p->n_type, 0, 0);
sp->n_lval = 0;
sp->n_rval = SP;
ecomp(buildtree(MINUSEQ, sp, p));
/* save the address of sp */
sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
sp->n_rval = SP;
t->n_type = sp->n_type;
ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
}
/*
* print out a constant node
* mat be associated with a label
*/
void
ninval(CONSZ off, int fsz, NODE *p)
{
union { float f; double d; int i[2]; } u;
struct symtab *q;
TWORD t;
#ifndef USE_GAS
int i, j;
#endif
t = p->n_type;
if (t > BTMASK)
t = INT; /* pointer */
if (p->n_op != ICON && p->n_op != FCON)
cerror("ninval: init node not constant");
if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
uerror("element not constant");
switch (t) {
case LONGLONG:
case ULONGLONG:
#ifdef USE_GAS
printf("\t.dword %lld\n", (long long)p->n_lval);
#else
i = p->n_lval >> 32;
j = p->n_lval & 0xffffffff;
p->n_type = INT;
if (bigendian) {
p->n_lval = j;
ninval(off, 32, p);
p->n_lval = i;
ninval(off+32, 32, p);
} else {
p->n_lval = i;
ninval(off, 32, p);
p->n_lval = j;
ninval(off+32, 32, p);
}
#endif
break;
case BOOL:
if (p->n_lval > 1)
p->n_lval = p->n_lval != 0;
/* FALLTHROUGH */
case INT:
case UNSIGNED:
printf("\t.word " CONFMT, (CONSZ)p->n_lval);
if ((q = p->n_sp) != NULL) {
if ((q->sclass == STATIC && q->slevel > 0)) {
printf("+" LABFMT, q->soffset);
} else
printf("+%s",
q->soname ? q->soname : exname(q->sname));
}
printf("\n");
break;
case SHORT:
case USHORT:
printf("\t.half %d\n", (int)p->n_lval & 0xffff);
break;
case CHAR:
case UCHAR:
printf("\t.byte %d\n", (int)p->n_lval & 0xff);
break;
case LDOUBLE:
case DOUBLE:
u.d = (double)p->n_dcon;
if (bigendian) {
printf("\t.word\t%d\n", u.i[0]);
//printf("\t.word\t%d\n", u.i[1]);
} else {
//printf("\t.word\t%d\n", u.i[1]);
printf("\t.word\t%d\n", u.i[0]);
}
break;
case FLOAT:
u.f = (float)p->n_dcon;
printf("\t.word\t0x%x\n", u.i[0]);
break;
default:
cerror("ninval");
}
}
/* make a name look like an external name in the local machine */
char *
exname(char *p)
{
if (p == NULL)
return "";
return p;
}
/*
* map types which are not defined on the local machine
*/
TWORD
ctype(TWORD type)
{
switch (BTYPE(type)) {
case LONG:
MODTYPE(type,INT);
break;
case ULONG:
MODTYPE(type,UNSIGNED);
}
return (type);
}
/* curid is a variable which is defined but
* is not initialized (and not a function );
* This routine returns the storage class for an uninitialized declaration
*/
int
noinit(void)
{
return(EXTERN);
}
void
calldec(NODE *p, NODE *q)
{
}
void
extdec(struct symtab *q)
{
}
/*
* Print out a string of characters.
* Assume that the assembler understands C-style escape
* sequences.
*/
void
instring(struct symtab *sp)
{
char *s, *str;
defloc(sp);
str = sp->sname;
/* be kind to assemblers and avoid long strings */
printf("\t.ascii \"");
for (s = str; *s != 0; ) {
if (*s++ == '\\') {
(void)esccon(&s);
}
if (s - str > 60) {
fwrite(str, 1, s - str, stdout);
printf("\"\n\t.ascii \"");
str = s;
}
}
fwrite(str, 1, s - str, stdout);
printf("\\0\"\n");
}
/* make a common declaration for id, if reasonable */
void
defzero(struct symtab *sp)
{
int off;
off = tsize(sp->stype, sp->sdf, sp->sap);
off = (off+(SZCHAR-1))/SZCHAR;
printf(" .%scomm ", sp->sclass == STATIC ? "l" : "");
if (sp->slevel == 0)
printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off);
else
printf(LABFMT ",0%o\n", sp->soffset, off);
}
#ifdef notdef
/* make a common declaration for id, if reasonable */
void
commdec(struct symtab *q)
{
int off;
off = tsize(q->stype, q->sdf, q->ssue);
off = (off+(SZCHAR-1))/SZCHAR;
printf(" .comm %s,%d\n", exname(q->soname), off);
}
/* make a local common declaration for id, if reasonable */
void
lcommdec(struct symtab *q)
{
int off;
off = tsize(q->stype, q->sdf, q->ssue);
off = (off+(SZCHAR-1))/SZCHAR;
if (q->slevel == 0)
printf("\t.lcomm %s,%d\n", exname(q->soname), off);
else
printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
}
/*
* print a (non-prog) label.
*/
void
deflab1(int label)
{
printf(LABFMT ":\n", label);
}
/* ro-text, rw-data, ro-data, ro-strings */
static char *loctbl[] = { "text", "data", "rdata", "rdata" };
void
setloc1(int locc)
{
if (locc == lastloc && locc != STRNG)
return;
if (locc == RDATA && lastloc == STRNG)
return;
if (locc != lastloc) {
lastloc = locc;
printf("\t.%s\n", loctbl[locc]);
}
if (locc == STRNG)
printf("\t.align 2\n");
}
#endif
/*
* Initialize a bitfield.
*/
void
infld(CONSZ off, int fsz, CONSZ val)
{
if (idebug)
printf("infld off %lld, fsz %d, val %lld inbits %d\n",
off, fsz, val, inbits);
val &= (1 << fsz)-1;
while (fsz + inbits >= SZCHAR) {
inval |= (val << inbits);
printf("\t.byte %d\n", inval & 255);
fsz -= (SZCHAR - inbits);
val >>= (SZCHAR - inbits);
inval = inbits = 0;
}
if (fsz) {
inval |= (val << inbits);
inbits += fsz;
}
}
/*
* set fsz bits in sequence to zero.
*/
void
zbits(OFFSZ off, int fsz)
{
int m;
if (idebug)
printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
if ((m = (inbits % SZCHAR))) {
m = SZCHAR - m;
if (fsz < m) {
inbits += fsz;
return;
} else {
fsz -= m;
printf("\t.byte %d\n", inval);
inval = inbits = 0;
}
}
if (fsz >= SZCHAR) {
printf("\t.zero %d\n", fsz/SZCHAR);
fsz -= (fsz/SZCHAR) * SZCHAR;
}
if (fsz) {
inval = 0;
inbits = fsz;
}
}
/*
* va_start(ap, last) implementation.
*
* f is the NAME node for this builtin function.
* a is the argument list containing:
* CM
* ap last
*
* It turns out that this is easy on MIPS. Just write the
* argument registers to the stack in va_arg_start() and
* use the traditional method of walking the stackframe.
*/
NODE *
mips_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
{
NODE *p, *q;
int sz = 1;
/* check num args and type */
if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
!ISPTR(a->n_left->n_type))
goto bad;
/* must first deal with argument size; use int size */
p = a->n_right;
if (p->n_type < INT) {
/* round up to word */
sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
}
p = buildtree(ADDROF, p, NIL); /* address of last arg */
p = optim(buildtree(PLUS, p, bcon(sz)));
q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
q = buildtree(CAST, q, p);
p = q->n_right;
nfree(q->n_left);
nfree(q);
p = buildtree(ASSIGN, a->n_left, p);
tfree(f);
nfree(a);
return p;
bad:
uerror("bad argument to __builtin_stdarg_start");
return bcon(0);
}
NODE *
mips_builtin_va_arg(NODE *f, NODE *a, TWORD t)
{
NODE *p, *q, *r;
int sz, tmpnr;
/* check num args and type */
if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
!ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
goto bad;
r = a->n_right;
/* get type size */
sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
if (sz < SZINT/SZCHAR) {
werror("%s%s promoted to int when passed through ...",
r->n_type & 1 ? "unsigned " : "",
DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
sz = SZINT/SZCHAR;
}
/* alignment */
p = tcopy(a->n_left);
if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
p = buildtree(PLUS, p, bcon(7));
p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
}
/* create a copy to a temp node */
q = tempnode(0, p->n_type, p->n_df, p->n_ap);
tmpnr = regno(q);
p = buildtree(ASSIGN, q, p);
q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
q = buildtree(PLUS, q, bcon(sz));
q = buildtree(ASSIGN, a->n_left, q);
q = buildtree(COMOP, p, q);
nfree(a->n_right);
nfree(a);
nfree(f);
p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
p = buildtree(UMUL, p, NIL);
p = buildtree(COMOP, q, p);
return p;
bad:
uerror("bad argument to __builtin_va_arg");
return bcon(0);
}
NODE *
mips_builtin_va_end(NODE *f, NODE *a, TWORD t)
{
tfree(f);
tfree(a);
return bcon(0);
}
NODE *
mips_builtin_va_copy(NODE *f, NODE *a, TWORD t)
{
if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
goto bad;
tfree(f);
f = buildtree(ASSIGN, a->n_left, a->n_right);
nfree(a);
return f;
bad:
uerror("bad argument to __buildtin_va_copy");
return bcon(0);
}
static int constructor;
static int destructor;
/*
* Give target the opportunity of handling pragmas.
*/
int
mypragma(char **ary)
{
if (strcmp(ary[1], "tls") == 0) {
uerror("thread-local storage not supported for this target");
return 1;
}
if (strcmp(ary[1], "constructor") == 0 || strcmp(ary[1], "init") == 0) {
constructor = 1;
return 1;
}
if (strcmp(ary[1], "destructor") == 0 || strcmp(ary[1], "fini") == 0) {
destructor = 1;
return 1;
}
return 0;
}
/*
* Called when a identifier has been declared, to give target last word.
*/
void
fixdef(struct symtab *sp)
{
if ((constructor || destructor) && (sp->sclass != PARAM)) {
printf("\t.section .%ctors,\"aw\",@progbits\n",
constructor ? 'c' : 'd');
printf("\t.p2align 2\n");
printf("\t.long %s\n", exname(sp->sname));
printf("\t.previous\n");
constructor = destructor = 0;
}
}
void
pass1_lastchance(struct interpass *ip)
{
}

Some files were not shown because too many files have changed in this diff Show More