Initial Import from SVN
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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 *~
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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 *);
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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.
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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<®list[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);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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/
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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)
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
@@ -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 > $@
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
|
||||
@@ -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 $<
|
||||
@@ -0,0 +1,4 @@
|
||||
void hello()
|
||||
{
|
||||
puts ("Hello, World!\n");
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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); }
|
||||
;
|
||||
|
||||
%%
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);}
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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"
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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, ®);
|
||||
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, ®);
|
||||
|
||||
if (p->n_right == NULL)
|
||||
p->n_op += (UCALL - CALL);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -0,0 +1,2 @@
|
||||
* Fix floating-point arguments in registers
|
||||
* Fix structure arguments in registers
|
||||
@@ -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], ®);
|
||||
else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
|
||||
param_64bit(sp[i], ®, xtemps && !saveallargs);
|
||||
else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
|
||||
param_double(sp[i], ®, xtemps && !saveallargs);
|
||||
else if (sp[i]->stype == FLOAT)
|
||||
param_float(sp[i], ®, xtemps && !saveallargs);
|
||||
else
|
||||
param_32bit(sp[i], ®, 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, ®num);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user