├── LICENSE ├── custom.mk ├── docs ├── cdb.pdf └── cdb3-spe.pdf ├── etc ├── linux.c ├── solaris.c └── win32.c ├── lookup.c ├── lookup.h ├── makefile ├── readme.html ├── src ├── cdb.c ├── client.c ├── clientstub.c ├── comm.c ├── comm.h ├── glue.h ├── inits.c ├── nub.c ├── nub.h ├── nub2.c ├── prelink.sh ├── server.c ├── server.h ├── stab.c ├── sym.asdl ├── symstub.c ├── symtab.c └── symtab.h ├── startup ├── irix.o ├── linux.o ├── osf.o ├── solaris.o ├── ultrix.o └── win32.obj └── wf.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) David R. Hanson. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 4 | software and associated documentation files (the "Software"), to deal in the Software 5 | without restriction, including without limitation the rights to use, copy, modify, 6 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 7 | permit persons to whom the Software is furnished to do so, subject to the following 8 | conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies 11 | or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 15 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 16 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 17 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 18 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | 21 | -------------------------------------------------------------------------------- /custom.mk: -------------------------------------------------------------------------------- 1 | # empty 2 | 3 | -------------------------------------------------------------------------------- /docs/cdb.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/docs/cdb.pdf -------------------------------------------------------------------------------- /docs/cdb3-spe.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/docs/cdb3-spe.pdf -------------------------------------------------------------------------------- /etc/linux.c: -------------------------------------------------------------------------------- 1 | /* x86s running Linux */ 2 | 3 | #include 4 | 5 | static char rcsid[] = "$Id$"; 6 | 7 | #ifndef LCCDIR 8 | #define LCCDIR "/usr/local/lib/lcc/" 9 | #endif 10 | 11 | char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; 12 | char inputs[256] = ""; 13 | char *cpp[] = { LCCDIR "gcc/cpp", 14 | "-U__GNUC__", "-D_POSIX_SOURCE", "-D__STDC__=1", "-D__STRICT_ANSI__", 15 | "-Dunix", "-Di386", "-Dlinux", 16 | "-D__unix__", "-D__i386__", "-D__linux__", "-D__signed__=signed", 17 | "$1", "$2", "$3", 0 }; 18 | char *include[] = {"-I" LCCDIR "include", "-I" LCCDIR "gcc/include", "-I/usr/include", 0 }; 19 | char *com[] = {LCCDIR "rcc", "-target=x86/linux", "", "$1", "$2", "$3", 0 }; 20 | char *as[] = { "/usr/bin/as", "-o", "$3", "$1", "$2", 0 }; 21 | static char *ld2[] = { 22 | /* 0 */ "/bin/sh", 23 | /* 1 */ LCCDIR "prelink.sh", "-o", 24 | /* 3 */ ".o", "$2", "\n", 25 | /* 6 */ "/usr/bin/ld", "-m", "elf_i386", "-dynamic-linker", 26 | /* 10 */ "/lib/ld-linux.so.2", "-o", "$3", 27 | /* 13 */ LCCDIR "startup.o", "/usr/lib/crti.o", 28 | /* 15 */ LCCDIR "gcc/crtbegin.o", "$1", "$2", 29 | /* 18 */ ".o", 30 | /* 19 */ "-L" LCCDIR, "-llcc", "-lnub", "-lnsl", 31 | /* 23 */ "-L" LCCDIR "gcc", "-lgcc", "-lm", "-lc", 32 | /* 27 */ "", 33 | /* 28 */ LCCDIR "gcc/crtend.o", "/usr/lib/crtn.o", 34 | /* 30 */ "\n", "/bin/rm", "-f", 35 | /* 33 */ ".o", 36 | /* 34 */ ".c", 37 | /* 35 */ 0 38 | }; 39 | char *ld[sizeof ld2/sizeof ld2[0]] = { 40 | /* 0 */ "/usr/bin/ld", "-m", "elf_i386", "-dynamic-linker", 41 | /* 4 */ "/lib/ld-linux.so.2", "-o", "$3", 42 | /* 7 */ "/usr/lib/crt1.o", "/usr/lib/crti.o", 43 | /* 9 */ LCCDIR "/gcc/crtbegin.o", 44 | "$1", "$2", 45 | /* 12 */ "-L" LCCDIR, 46 | /* 13 */ "-llcc", 47 | /* 14 */ "-L" LCCDIR "/gcc", "-lgcc", "-lc", "-lm", 48 | /* 18 */ "", 49 | /* 19 */ LCCDIR "/gcc/crtend.o", "/usr/lib/crtn.o", 50 | 0 }; 51 | 52 | extern char *concat(char *, char *); 53 | extern char *stringf(const char *, ...); 54 | 55 | int option(char *arg) { 56 | if (strncmp(arg, "-lccdir=", 8) == 0) { 57 | cpp[0] = concat(&arg[8], "/gcc/cpp"); 58 | include[0] = stringf("-I%s/include", &arg[8]); 59 | include[1] = stringf("-I%s/gcc/include", &arg[8]); 60 | ld[9] = concat(&arg[8], "/gcc/crtbegin.o"); 61 | ld[12] = concat("-L", &arg[8]); 62 | ld[14] = stringf("-L%s/gcc",&arg[8]); 63 | ld[19] = concat(&arg[8], "/gcc/crtend.o"); 64 | ld2[1] = concat(&arg[8], "/prelink.sh"); 65 | ld2[13] = concat(&arg[8], "/startup.o"); 66 | ld2[15] = concat(&arg[8], "/gcc/crtbegin.o"); 67 | ld2[19] = concat("-L", &arg[8]); 68 | ld2[23] = stringf("-L%s/gcc", &arg[8]); 69 | ld2[28] = concat(&arg[8], "/gcc/crtend.o"); 70 | com[0] = concat(&arg[8], "/rcc"); 71 | } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-pg") == 0) { 72 | ld[7] = "/usr/lib/gcrt1.o"; 73 | ld[18] = "-lgmon"; 74 | } else if (strcmp(arg, "-b") == 0) 75 | ; 76 | else if (strcmp(arg, "-g") == 0) 77 | ; 78 | else if (strncmp(arg, "-ld=", 4) == 0) 79 | ld[0] = &arg[4]; 80 | else if (strcmp(arg, "-static") == 0) { 81 | ld[3] = "-static"; 82 | ld[4] = ""; 83 | } else if (strcmp(arg, "-g4") == 0) { 84 | extern char *tempdir; 85 | extern int getpid(void); 86 | ld2[3] = stringf("%s/%d.o", tempdir, getpid()); 87 | ld2[18] = ld2[3]; 88 | ld2[33] = ld2[3]; 89 | ld2[34] = stringf("%s/%d.c", tempdir, getpid()); 90 | memcpy(ld, ld2, sizeof ld2); 91 | com[2] = "-g4"; 92 | } else 93 | return 0; 94 | return 1; 95 | } 96 | -------------------------------------------------------------------------------- /etc/solaris.c: -------------------------------------------------------------------------------- 1 | /* SPARCs running Solaris 2.5.1 at CS Dept., Princeton University */ 2 | 3 | #include 4 | 5 | static char rcsid[] = "$Id$"; 6 | 7 | #ifndef LCCDIR 8 | #define LCCDIR "/usr/local/lib/lcc/" 9 | #endif 10 | #ifndef SUNDIR 11 | #define SUNDIR "/opt/SUNWspro/SC4.0/lib/" 12 | #endif 13 | 14 | static char lccdir[512] = LCCDIR; 15 | char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; 16 | char inputs[256] = ""; 17 | char *cpp[] = { LCCDIR "cpp", 18 | "-D__STDC__=1", "-Dsparc", "-D__sparc__", "-Dsun", "-D__sun__", "-Dunix", 19 | "$1", "$2", "$3", 0 }; 20 | char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", 21 | "-I/usr/include", 0 }; 22 | char *com[] = { LCCDIR "rcc", "-target=sparc/solaris", "", 23 | "$1", "$2", "$3", 0 }; 24 | char *as[] = { "/usr/ccs/bin/as", "-Qy", "-s", "-o", "$3", "$1", "$2", 0 }; 25 | static char *ld2[] = { 26 | /* 0 */ "/bin/sh", 27 | /* 1 */ LCCDIR "prelink.sh", "-o", 28 | /* 3 */ ".o", "$2", "\n", 29 | /* 6 */ "/usr/ccs/bin/ld", "-o", "$3", "$1", SUNDIR "crti.o", 30 | /* 11 */ SUNDIR "startup.o", SUNDIR "values-xa.o", "$2", 31 | /* 14 */ ".o", "-Y", 32 | /* 16 */ "P," SUNDIR ":/usr/ccs/lib:/usr/lib", "-Qy", 33 | /* 18 */ "-L" LCCDIR, "-llcc", "-lnub", "-lsocket", "-lnsl", "-lm", "-lc", SUNDIR "crtn.o", 34 | /* 26 */ "\n", "/bin/rm", "-f", 35 | /* 29 */ ".o", 36 | /* 30 */ ".c", 37 | /* 31 */ 0 38 | }; 39 | char *ld[sizeof ld2/sizeof ld2[0]] = { 40 | /* 0 */ "/usr/ccs/bin/ld", "-o", "$3", "$1", SUNDIR "crti.o", 41 | /* 5 */ SUNDIR "crt1.o", SUNDIR "values-xa.o", "$2", "-Y", 42 | /* 9 */ "P," SUNDIR ":/usr/ccs/lib:/usr/lib", "-Qy", 43 | /* 11 */ "-L" LCCDIR, "-llcc", "-lm", "-lc", SUNDIR "crtn.o", 44 | /* 16 */ 0 45 | }; 46 | 47 | extern char *stringf(const char *, ...); 48 | 49 | int option(char *arg) { 50 | if (strncmp(arg, "-lccdir=", 8) == 0) { 51 | strcpy(lccdir, &arg[8]); 52 | if (lccdir[strlen(lccdir)-1] == '/') 53 | lccdir[strlen(lccdir)-1] = '\0'; 54 | cpp[0] = stringf("%s/cpp", lccdir); 55 | include[0] = stringf("-I%s/include", lccdir); 56 | ld[11] = stringf("-L%s", lccdir); 57 | com[0] = stringf("%s/rcc", lccdir); 58 | ld2[1] = stringf("%s/prelink.sh", lccdir); 59 | ld2[11] = stringf("%s/startup.o", lccdir); 60 | ld2[18] = ld[11]; 61 | } else if (strcmp(arg, "-g") == 0) 62 | ; 63 | else if (strcmp(arg, "-p") == 0) { 64 | ld[5] = SUNDIR "mcrt1.o"; 65 | ld[9] = "P," SUNDIR "libp:/usr/ccs/lib/libp:/usr/lib/libp:" 66 | SUNDIR ":/usr/ccs/lib:/usr/lib"; 67 | } else if (strcmp(arg, "-b") == 0) 68 | ; 69 | else if (strncmp(arg, "-ld=", 4) == 0) { 70 | ld[0] = &arg[4]; 71 | ld2[0] = &arg[4]; 72 | } else if (strcmp(arg, "-g4") == 0) { 73 | extern char *tempdir; 74 | extern int getpid(void); 75 | ld2[3] = stringf("%s/%d.o", tempdir, getpid()); 76 | ld2[14] = ld2[3]; 77 | ld2[29] = ld2[3]; 78 | ld2[30] = stringf("%s/%d.c", tempdir, getpid()); 79 | memcpy(ld, ld2, sizeof ld2); 80 | com[2] = "-g4"; 81 | } else 82 | return 0; 83 | return 1; 84 | } 85 | -------------------------------------------------------------------------------- /etc/win32.c: -------------------------------------------------------------------------------- 1 | /* x86s running MS Windows NT 4.0 */ 2 | 3 | #include 4 | #include 5 | 6 | static char rcsid[] = "$Id$"; 7 | 8 | #ifndef LCCDIR 9 | #define LCCDIR "\\progra~1\\lcc\\4.1\\bin\\" 10 | #endif 11 | 12 | static char lccdir[512] = LCCDIR; 13 | char *suffixes[] = { ".c;.C", ".i;.I", ".asm;.ASM;.s;.S", ".obj;.OBJ", ".exe", 0 }; 14 | char inputs[256] = ""; 15 | char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1", "-Dwin32", "-D_WIN32", "-D_M_IX86", 16 | "$1", "$2", "$3", 0 }; 17 | char *include[] = { 18 | "-I" LCCDIR "include", 19 | "-I\"/program files/devstudio/vc/include\"", 20 | "-I/msdev/include", 0 }; 21 | char *com[] = { LCCDIR "rcc", "-target=x86/win32", "", "$1", "$2", "$3", 0 }; 22 | char *as[] = { "ml", "-nologo", "-c", "-Cp", "-coff", "-Fo$3", "$1", "$2", 0 }; 23 | static char *ld2[] = { 24 | /* 0 */ "sh", 25 | /* 1 */ LCCDIR "prelink.sh", "-o", 26 | /* 3 */ ".obj", "$2", "\n", 27 | /* 6 */ "link", "-nologo", "-align:0x1000", "-subsystem:console", "-entry:mainCRTStartup", 28 | /* 11 */ "-OUT:$3", "$1", "$2", 29 | /* 14 */ ".obj", 30 | /* 15 */ LCCDIR "startup.obj", 31 | /* 16 */ LCCDIR "libnub.lib", 32 | /* 17 */ "ws2_32.lib", 33 | /* 18 */ LCCDIR "liblcc.lib", "libc.lib", "kernel32.lib", "\n", 34 | /* 22 */ "rm", "-f", 35 | /* 24 */ ".obj", 36 | /* 25 */ ".c", 37 | 0 38 | }; 39 | char *ld[sizeof ld2/sizeof ld2[0]] = { 40 | /* 0 */ "link", "-nologo", "-align:0x1000", "-subsystem:console", "-entry:mainCRTStartup", 41 | /* 5 */ "$2", "-OUT:$3", "$1", 42 | /* 8 */ LCCDIR "liblcc.lib", "libc.lib", "kernel32.lib", 43 | /* 11 */ 0 44 | }; 45 | 46 | extern char *stringf(const char *, ...); 47 | extern char *replace(const char *, int, int); 48 | 49 | int option(char *arg) { 50 | if (strncmp(arg, "-lccdir=", 8) == 0) { 51 | strcpy(lccdir, replace(arg + 8, '/', '\\')); 52 | if (lccdir[strlen(lccdir)-1] == '\\') 53 | lccdir[strlen(lccdir)-1] = '\0'; 54 | cpp[0] = stringf("%s\\cpp.exe", lccdir); 55 | include[0] = stringf("-I%s\\include", lccdir); 56 | com[0] = stringf("%s\\rcc.exe", lccdir); 57 | ld[8] = stringf("%s\\liblcc.lib", lccdir); 58 | ld2[1] = stringf("%s\\prelink.sh", lccdir); 59 | ld2[15] = stringf("%s\\startup.obj", lccdir); 60 | ld2[16] = stringf("%s\\libnub.lib", lccdir); 61 | ld2[18] = ld[8]; 62 | } else if (strcmp(arg, "-b") == 0) 63 | ; 64 | else if (strncmp(arg, "-ld=", 4) == 0) 65 | ld[0] = &arg[4]; 66 | else if (strcmp(arg, "-g4") == 0) { 67 | extern char *tempdir; 68 | ld2[3] = stringf("%s\\%d.obj", tempdir, getpid()); 69 | ld2[14] = ld2[3]; 70 | ld2[24] = ld2[3]; 71 | ld2[25] = stringf("%s\\%d.c", tempdir, getpid()); 72 | memcpy(ld, ld2, sizeof ld2); 73 | com[2] = "-g4"; 74 | } else 75 | return 0; 76 | return 1; 77 | } 78 | -------------------------------------------------------------------------------- /lookup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "lookup.h" 5 | 6 | static void err(char *s) { 7 | printf("? %s\n", s); 8 | exit(1); 9 | } 10 | 11 | static struct node words[2000]; 12 | static int next = 0; 13 | 14 | struct node *lookup(char *word, struct node **p) { 15 | if (*p) { 16 | int cond = strcmp(word, (*p)->word); 17 | if (cond < 0) 18 | return lookup(word, &(*p)->left); 19 | else if (cond > 0) 20 | return lookup(word, &(*p)->right); 21 | else 22 | return *p; 23 | } 24 | if (next >= sizeof words/sizeof words[0]) 25 | err("out of node storage"); 26 | words[next].count = 0; 27 | words[next].left = words[next].right = NULL; 28 | words[next].word = malloc(strlen(word) + 1); 29 | if (words[next].word == NULL) 30 | err("out of word storage"); 31 | strcpy(words[next].word, word); 32 | return *p = &words[next++]; 33 | } 34 | -------------------------------------------------------------------------------- /lookup.h: -------------------------------------------------------------------------------- 1 | struct node { 2 | int count; /* number of occurrences */ 3 | struct node *left; /* left subtree */ 4 | struct node *right; /* right subtree */ 5 | char *word; /* pointer to the word */ 6 | }; 7 | extern struct node *lookup(char *, struct node **); 8 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | CC=cc 3 | CFLAGS = -g 4 | # Configuration: 5 | # SRCDIR root of the lcc 4.1 distribution 6 | # INCLUDES -I options for CII headers and lcc 4.1 headers 7 | # HOSTFILE path to an lcc driver back end that supports cdb 8 | # BUILDDIR the lcc 4.1 build directory 9 | # LDFLAGS -L options for librcc.a (in the lcc build directory) 10 | # LIBS libraries, including socket and network libraries 11 | SRCDIR = /u/drh/pkg/lcc/4.1 12 | INCLUDES= -I/usr/local/lib/cii/1/include -I$(SRCDIR)/src -I$(ASDL_HOME)/include/asdlGen -I$(BUILDDIR) 13 | HOSTFILE= etc/solaris.c 14 | BUILDDIR= $(SRCDIR)/sparc-solaris 15 | LDFLAGS = -g -L$(BUILDDIR) -L$(ASDL_HOME)/lib/asdlGen 16 | LIBS = -lasdl -lcii -lsocket -lnsl 17 | E= 18 | O=.o 19 | A=.a 20 | CUSTOM=custom.mk 21 | include $(CUSTOM) 22 | 23 | B=$(BUILDDIR)/ 24 | 25 | all:: libnub cdb rcc lcc prelink 26 | 27 | prelink: $Bprelink.sh 28 | lcc: $Blcc$E 29 | rcc: $Brcc$E 30 | libnub: $Blibnub$A 31 | cdb: $Bcdb$E 32 | 33 | $Blcc$E: $Blcc$O $Bhost$O; $(CC) $(LDFLAGS) -o $@ $Blcc$O $Bhost$O 34 | 35 | $Blcc$O: $(SRCDIR)/etc/lcc.c; $(CC) -c $(CFLAGS) -o $@ $(SRCDIR)/etc/lcc.c 36 | $Bhost$O: $(HOSTFILE); $(CC) -c $(CFLAGS) -o $@ $(HOSTFILE) 37 | 38 | $Blibnub$A: $Bclient$O $Bnub$O $Bcomm$O 39 | ar ruv $@ $? 40 | 41 | $Bprelink.sh: src/prelink.sh; cp src/prelink.sh $@; chmod +x $@ 42 | 43 | $Brcc$E: $Bstab$O $Binits$O $Bsym$O 44 | $(CC) $(LDFLAGS) -o $@ $Bstab$O $Binits$O $Bsym$O -lrcc -L$(ASDL_HOME)/lib/asdlGen -lasdl -lcii 45 | 46 | $Binits$O: src/inits.c; $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ src/inits.c 47 | 48 | CDBOBJS=$Bserver$O \ 49 | $Bcomm$O \ 50 | $Bcdb$O \ 51 | $Bsym$O \ 52 | $Bsymtab$O \ 53 | $Bnub2$O 54 | 55 | $Bcdb$E: $(CDBOBJS) 56 | $(CC) $(LDFLAGS) -o $@ $(CDBOBJS) $(LIBS) 57 | 58 | $Bcdb$O: src/cdb.c src/server.h src/glue.h src/nub.h src/symtab.h $Bsym.h 59 | $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ src/cdb.c 60 | 61 | $Bcomm$O: src/comm.c src/comm.h src/server.h 62 | $(CC) -c $(CFLAGS) -o $@ src/comm.c 63 | 64 | $Bserver$O: src/server.c src/comm.h src/glue.h src/nub.h src/server.h src/symtab.h $Bsym.h 65 | $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ src/server.c 66 | 67 | $Bclient$O: src/client.c src/comm.h src/glue.h src/nub.h src/server.h 68 | $(CC) -c $(CFLAGS) -o $@ src/client.c 69 | 70 | $Bnub$O: src/nub.c src/nub.h src/glue.h 71 | $(CC) -c $(CFLAGS) -I$(SRCDIR)/src -o $@ src/nub.c 72 | 73 | $Bnub2$O: src/nub2.c src/nub.h src/glue.h 74 | $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ src/nub2.c 75 | 76 | $Bsymtab$O: src/symtab.c src/symtab.h src/glue.h 77 | $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ src/symtab.c 78 | 79 | $Bstab$O: src/stab.c src/glue.h $Bsym.h 80 | $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ src/stab.c 81 | 82 | $Bsym.h: src/sym.asdl 83 | $(ASDL_HOME)/bin/asdlGen --c -d $B src/sym.asdl 84 | 85 | $Bsym$O: $Bsym.h 86 | $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ $Bsym.c 87 | 88 | STUBOBJS=$Bcdb$O \ 89 | $Bsym$O \ 90 | $Bsymtab$O \ 91 | $Bnub2$O 92 | 93 | stubtest: wf.c lookup.c $(STUBOBJS) 94 | $Blcc -Wo-lccdir=$(BUILDDIR) -v -Wo-g4 wf.c lookup.c $(STUBOBJS) \ 95 | `if [ -d c:/ ]; then echo '$(ASDL_HOME)/lib/asdlGen/libasdl.lib' libcii.lib; \ 96 | else echo -L$(ASDL_HOME)/lib/asdlGen -lasdl -lcii; fi` 97 | 98 | test: wf.c lookup.c $Blibnub$A $Bcdb$E 99 | $Blcc -Wo-lccdir=$(BUILDDIR) -v -Wo-g4 wf.c lookup.c 100 | 101 | clean:: 102 | rm -f $B*$O 103 | 104 | clobber:: clean 105 | rm -f $Blibnub$A $Bcdb$E $Brcc$E $Blcc$E $Bprelink.sh 106 | -------------------------------------------------------------------------------- /readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cdb 3.1 6 | 7 | 8 | 9 | 10 | 11 |

cdb 3.1

12 | 13 |

This hierarchy holds the implementation of cdb version 3.1, the debugger described in 14 | D. R. Hanson, 15 | ‘A Machine-Independent Debugger—Revisited’, 16 | Software—Practice and Experience 29 (10), 849-862, Aug. 1999; 17 | PDF.

18 | 19 |

The initial version of cdb is described in 20 | D. R. Hanson and M. Raghavachari, 21 | ‘A Machine-Independent Debugger’, 22 | Software—Practice and Experience 26 (11), 1277-1299, Nov. 1996; 23 | PDF.

24 | 25 |

Contents

26 | 27 |
28 |
readme.html
29 |
this file.
30 |
makefile
31 |
make instructions for building cdb.
32 |
lookup.[ch] wf.c
33 |
sample program described in ‘A Machine-Independent Debugger’.
34 |
src/*.[ch]
35 |
source code for cdb, the nub, the RPC code, the prelinker script, and the symbol-table 36 | emitter additions to lcc.
37 |
etc/*.c
38 |
lcc driver back ends modified to support the -Wo-g4 option.
39 |
startup/{*.o,*.obj}
40 |
platform-specific startup code modified to start the nub. Only startup/solaris.o, 41 | startup/linux.o, and startup/win32.obj have been tested.
42 |
docs/*.pdf
43 |
PDFs for the papers cited above.
44 |
45 | 46 |

Differences

47 | 48 |

‘A Machine-Independent Debugger’ describes the initial version of cdb. The list below 49 | summarizes the differences between version 3.1 and cdb 2.2. For all the details, see 50 | ‘A Machine-Independent Debugger—Revisited’.

51 | 52 |

This version works only with lcc 4.1, and it requires the ASDL generator, 53 | asdlGen), 54 | and the C Interfaces and Implementations (CII) library.

55 | 56 |

In the two-process version, cdb is the server and the target (the program being 57 | debugged) is the client. src/server.c is the 58 | server side of the RPC channel and src/client.c is 59 | the client side. (These roles are reversed in Table 1 and Figure 6 in the initial cdb 60 | paper.) cdb can run on a different machine than the target, but the machines must have the 61 | same type metrics and endianness.

62 | 63 |

All strings, types, and symbol-table entries are stored in an ASDL ‘pickle’, 64 | which is named X.pickle, where X is the unique module 65 | identifier. src/sym.asdl defines the relevant data 66 | structures. cdb reads pickles when a client attaches.

67 | 68 |

Modules hold only an unique module identifier and a pointer to an array of addresses of 69 | globals and statics, which is stored in read-only memory.

70 | 71 |

_Nub_bp takes only one argument, the index of the stopping point i, and 72 | switches to cdb if _Nub_bpflags[i] is nonzero. cdb determines if a breakpoint 73 | i is set in the module that caused the switch; if no breakpoint is set, 74 | control is returned to the client.

75 | 76 |

Installation

77 | 78 |

This version of cdb has been installed and (lightly) tested on RedHat Linux 2.1, 79 | Solaris 2.5.1, and Windows NT 4.0. Installation involves building cdb, the nub library (libnub.a), 80 | and rebuilding rcc (lcc's compiler proper) and lcc (lcc's compilation driver).

81 | 82 |

The following steps describe the installation under Solaris and Linux. Similar steps 83 | apply to Windows NT 4.0. Under NT, you'll need a UNIX-style shell and Visual C++ 5.0 or 84 | 6.0. 85 | 86 |

    87 |
  1. Install lcc 4.1, asdlGen 1.2, and the CII library.
  2. 88 |
  3. Create a file, custom.mk, that redefines the definitions at the top of the 89 | makefile to suit your local configuration. Make sure BUILDDIR points to the 90 | lcc 4.1 build directory (or a copy of it) and ASDL_HOME points to the root of 91 | the asdlGen installation.
  4. 92 |
  5. Edit etc/solaris.c 93 | or etc/linux.c 94 | (or a copy) to suit your local configuration, and set HOSTNAME to the name of 95 | the appropriate file in custom.mk. These files are variants of the driver 96 | back ends included in the lcc 4.1 distribution. They support the -Wo-g4 option, which 97 | causes lcc to emit cdb-style symbol tables as ASDL pickles.
  6. 98 |
  7. Linux doesn't have -lsocket (the socket library), so, if you're running on 99 | Linux, redefine LIBS in custom.mk; e.g., I use
    100 |
    LIBS=-lasdl -lcii -lnsl
    101 |
    102 |
  8. 103 |
  9. Run make:
    104 |
    1% make CUSTOM=custom.mk
    105 |
    106 |

    You can omit the assignment if your local configuration is in custom.mk. I 107 | use different names for different platforms, e.g.,

    108 |
    109 |
    1% make CUSTOM=linux.mk
    110 |
    111 |

    Depending on the values of file timestamps, you might have to touch etc/solaris.c, 113 | etc/linux.c, 114 | or src/inits.c, 115 | or remove the corresponding object 116 | files, to force rebuilding of lcc or rcc. IMPORTANT: Use the same C 117 | compiler you used to build lcc.

    118 |
  10. 119 |
  11. Copy the startup code to the build directory, e.g.,
    120 |
    1% cp startup/solaris.o ${BUILDDIR}/startup.o
    121 |
    122 |

    Notice that the name of the installed startup code is always startup.o.

    123 |
  12. 124 |
  13. Test the single-process version of cdb by building the sample program:
    125 |
    1% make CUSTOM=custom.mk stubtest
    126 |
    127 |

    Then run a.out:

    128 |
    129 |
    1% a.out
    130 | fetching module [1571580302] inhaling lookup.c[1571580302]
    131 | fetching module [1571580299] inhaling wf.c[1571580299]
    132 | cdb>
    133 |
    134 |

    The documentation in ‘A Machine-Independent Debugger’ applies; the 135 | ‘h’ command summarizes the commands.

    136 |
  14. 137 |
  15. Test the two-process version of cdb. Build the sample program with
    138 |
    1% make CUSTOM=custom.mk test
    139 |
    140 |

    Then run cdb:

    141 |
    142 |
    1% ${BUILDDIR}/cdb
    143 | /u/drh/pkg/4.1/sparc-solaris/cdb listening on 0.0.0.0:9001
    144 |
    145 |

    In a separate window, set the DEBUGGER environment variable and run a.out:

    146 |
    147 |
    2% setenv DEBUGGER localhost:9001
    148 | 2% a.out
    149 | client: connected on 127.0.0.1:47632 to 127.0.0.1:9001
    150 |
    151 |

    In the cdb window, you should see something like:

    152 |
    153 |
    /u/drh/pkg/4.1/sparc-solaris/cdb: now serving 127.0.0.1:1428
    154 | fetching module [1571576238] inhaling wf.c[1571576238]
    155 | fetching module [1571576369] inhaling lookup.c[1571576369]
    156 | cdb>
    157 |
    158 |

    When you exit the client, cdb waits for another connection.

    159 |
  16. 160 |
  17. The command make CUSTOM=custom.mk clean; cleans up.
  18. 161 |
  19. (Optional) Add a link to cdb from /usr/local/bin, e.g.,
    162 |
    1% ln -s ${BUILDDIR}/cdb /usr/local/bin/cdb
    163 |
    164 |
  20. 165 |
166 | 167 |

Bugs and Suggestions

168 | 169 |

Send me email. I can’t promise 170 | timely responses or patches, but I intend to keep cdb in sync with lcc.

171 | 172 |
173 | 174 |
175 | David R. Hanson 176 |
177 | 178 | 179 | -------------------------------------------------------------------------------- /src/cdb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "mem.h" 8 | #include "seq.h" 9 | #include "server.h" 10 | #include "symtab.h" 11 | 12 | static char rcsid[] = "$Id$"; 13 | 14 | struct cdb_src { 15 | int n; 16 | Nub_coord_T first; 17 | }; 18 | 19 | static FILE *in, *out; 20 | static Nub_state_T focus; 21 | static int frameno; 22 | static Nub_coord_T bkpts[100]; 23 | static int nbpts; 24 | static Nub_coord_T *brkpt = NULL; 25 | 26 | static void onbreak(Nub_state_T); 27 | 28 | /* 29 | memcmp is defined here because some vendors (eg, Sun) don't implement 30 | it, strcmp, or strncmp correctly; they must treat the bytes 31 | as unsigned chars. 32 | */ 33 | int memcmp(const void *s1, const void *s2, size_t n) { 34 | const unsigned char *cs1 = s1, *cs2 = s2; 35 | 36 | for ( ; n-- > 0; cs1++, cs2++) 37 | if (*cs1 != *cs2) 38 | return *cs1 - *cs2; 39 | return 0; 40 | } 41 | 42 | static int getvalue(void *address, void *buf, int size) { 43 | int n; 44 | 45 | n = _Nub_fetch(0, address, buf, size); 46 | assert(n == size); 47 | return n; 48 | } 49 | 50 | static void put(char *fmt, ...) { 51 | va_list ap; 52 | 53 | va_start(ap, fmt); 54 | vfprintf(out, fmt, ap); 55 | va_end(ap); 56 | } 57 | 58 | static void tput(int uname, int uid); 59 | 60 | static void ftput(Seq_T fields, int uname) { 61 | int i, count = Seq_length(fields); 62 | 63 | put("{"); 64 | for (i = 0; i < count; i++) { 65 | sym_field_ty f = Seq_get(fields, i); 66 | tput(uname, f->type); 67 | put(" %s; ", f->id); 68 | } 69 | put("}"); 70 | } 71 | 72 | static void tput(int uname, int uid) { 73 | sym_type_ty ty = _Sym_type(uname, uid); 74 | 75 | assert(ty); 76 | switch (ty->kind) { 77 | case sym_CONST_enum: 78 | put("const "); 79 | tput(uname, ty->v.sym_CONST.type); 80 | break; 81 | case sym_VOLATILE_enum: 82 | put("volatile "); 83 | tput(uname, ty->v.sym_VOLATILE.type); 84 | break; 85 | case sym_POINTER_enum: { 86 | sym_type_ty rty = _Sym_type(uname, ty->v.sym_POINTER.type); 87 | if (rty->kind == sym_STRUCT_enum) 88 | put("struct %s ", rty->v.sym_STRUCT.tag); 89 | else if (rty->kind == sym_UNION_enum) 90 | put("union %s ", rty->v.sym_UNION.tag); 91 | else if (rty->kind != sym_POINTER_enum) { 92 | tput(uname, ty->v.sym_POINTER.type); 93 | put(" "); 94 | } else 95 | tput(uname, ty->v.sym_POINTER.type); 96 | put("*"); 97 | break; 98 | } 99 | case sym_ARRAY_enum: 100 | tput(uname,ty->v.sym_ARRAY.type); 101 | if (ty->v.sym_ARRAY.nelems > 0) 102 | put("[%d]", ty->v.sym_ARRAY.nelems); 103 | else 104 | put("[]"); 105 | break; 106 | case sym_FUNCTION_enum: { 107 | int i, count = Seq_length(ty->v.sym_FUNCTION.formals); 108 | tput(uname, ty->v.sym_FUNCTION.type); 109 | put(" ("); 110 | for (i = 0; i < count; i++) { 111 | if (i > 0) 112 | put(","); 113 | tput(uname, *(int *)Seq_get(ty->v.sym_FUNCTION.formals, i)); 114 | } 115 | put(")"); 116 | break; 117 | } 118 | case sym_STRUCT_enum: 119 | put("struct %s ", ty->v.sym_STRUCT.tag); 120 | ftput(ty->v.sym_STRUCT.fields, uname); 121 | break; 122 | case sym_UNION_enum: 123 | put("union %s ", ty->v.sym_UNION.tag); 124 | ftput(ty->v.sym_UNION.fields, uname); 125 | break; 126 | case sym_ENUM_enum: { 127 | int i, count = Seq_length(ty->v.sym_ENUM.ids); 128 | put("enum %s {", ty->v.sym_ENUM.tag); 129 | for (i = 0; i < count; i++) { 130 | sym_enum__ty e = Seq_get(ty->v.sym_ENUM.ids, i); 131 | if (i > 0) 132 | put(","); 133 | put("%s=%d", e->id, e->value); 134 | } 135 | put("}"); 136 | break; 137 | } 138 | case sym_VOID_enum: put("void"); break; 139 | #define xx(t) if (ty->size == sizeof (t)) do { put(#t); return; } while (0) 140 | case sym_FLOAT_enum: 141 | xx(float); 142 | xx(double); 143 | xx(long double); 144 | assert(0); 145 | case sym_INT_enum: 146 | xx(char); 147 | xx(short); 148 | xx(int); 149 | xx(long); 150 | assert(0); 151 | case sym_UNSIGNED_enum: 152 | xx(unsigned char); 153 | xx(unsigned short); 154 | xx(unsigned int); 155 | xx(unsigned long); 156 | assert(0); 157 | #undef xx 158 | default:assert(0); 159 | } 160 | } 161 | 162 | static void sput(char *address, int max) { 163 | int i, j; 164 | unsigned char buf[4]; 165 | 166 | put("\""); 167 | for (i = 0; i < max; i += (int)sizeof buf) { 168 | getvalue(address + i, buf, sizeof buf); 169 | for (j = 0; j < (int)sizeof buf; j++) 170 | if (buf[j] == 0) { 171 | put("\""); 172 | return; 173 | } else if (buf[j] < ' ' || buf[j] >= 0177) 174 | put("\\x%02x", buf[j]); 175 | else 176 | put("%c", buf[j]); 177 | } 178 | put("..."); 179 | } 180 | 181 | static void vput(int uname, int uid, char *address); 182 | 183 | static void fvput(Seq_T fields, int uname, void *address) { 184 | int i, count = Seq_length(fields); 185 | 186 | put("{"); 187 | for (i = 0; i < count; i++) { 188 | sym_field_ty f = Seq_get(fields, i); 189 | if (i > 0) 190 | put(","); 191 | put("%s=", f->id); 192 | if (f->bitsize > 0) { 193 | unsigned buf; 194 | sym_type_ty fty = _Sym_type(uname, f->type); 195 | getvalue((char *)address + f->offset, &buf, sizeof (unsigned)); 196 | buf >>= f->lsb; 197 | if (fty->kind == sym_UNSIGNED_enum || (buf&(1<<(f->bitsize-1))) == 0) 198 | put("%u", f->bitsize == 8*sizeof buf ? buf : buf&(~(~0UL<bitsize))); 199 | else 200 | put("%d", f->bitsize == 8*sizeof buf ? buf : (~0UL<bitsize)|buf); 201 | } else 202 | vput(uname, f->type, (char *)address + f->offset); 203 | } 204 | put("}"); 205 | } 206 | 207 | static void vput(int uname, int uid, char *address) { 208 | sym_type_ty ty = _Sym_type(uname, uid); 209 | 210 | if (address == NULL) { 211 | put("?"); 212 | return; 213 | } 214 | switch (ty->kind) { 215 | case sym_CONST_enum: 216 | vput(uname, ty->v.sym_CONST.type, address); 217 | break; 218 | case sym_VOLATILE_enum: 219 | vput(uname, ty->v.sym_VOLATILE.type, address); 220 | break; 221 | case sym_FUNCTION_enum: { 222 | void *p; 223 | put("("); 224 | tput(uname, uid); 225 | put(")"); 226 | getvalue(address, &p, ty->size); 227 | put("0X%x", p); 228 | break; 229 | } 230 | case sym_POINTER_enum: { 231 | void *p; 232 | put("("); 233 | tput(uname, uid); 234 | put(")"); 235 | getvalue(address, &p, ty->size); 236 | put("0X%x", p); 237 | if (p != NULL && _Sym_type(uname, ty->v.sym_POINTER.type)->size == 1) { 238 | put(" "); 239 | sput(p, 80); 240 | } 241 | break; 242 | } 243 | case sym_ARRAY_enum: { 244 | char prev[1024], buf[1024]; 245 | int size = _Sym_type(uname, ty->v.sym_ARRAY.type)->size; 246 | if (ty->v.sym_ARRAY.nelems > 0 && size == 1) { 247 | put("{"); 248 | sput(address, 80); 249 | put("}"); 250 | } else if (ty->v.sym_ARRAY.nelems > 10 && size <= sizeof buf) { 251 | int i; 252 | put("{"); 253 | for (i = 0; i < ty->v.sym_ARRAY.nelems - 1; ) { 254 | put("\n [%d]=", i); 255 | vput(uname, ty->v.sym_ARRAY.type, address); 256 | getvalue(address, prev, size); 257 | while (++i < ty->v.sym_ARRAY.nelems - 1) { 258 | address += size; 259 | getvalue(address, buf, size); 260 | if (memcmp(prev, buf, size) != 0) 261 | break; 262 | } 263 | } 264 | put("\n [%d]=", i); 265 | vput(uname, ty->v.sym_ARRAY.type, address); 266 | put("\n}"); 267 | } else if (ty->v.sym_ARRAY.nelems > 0) { 268 | int i; 269 | put("{"); 270 | vput(uname, ty->v.sym_ARRAY.type, address); 271 | for (i = 1; i < ty->v.sym_ARRAY.nelems; i++) { 272 | put(","); 273 | address = (char *)address + size; 274 | vput(uname, ty->v.sym_ARRAY.type, address); 275 | } 276 | put("}"); 277 | } else 278 | put("0X%x", address); 279 | break; 280 | } 281 | case sym_STRUCT_enum: 282 | fvput(ty->v.sym_STRUCT.fields, uname, address); 283 | break; 284 | case sym_UNION_enum: 285 | fvput(ty->v.sym_UNION.fields, uname, address); 286 | break; 287 | case sym_ENUM_enum: { 288 | int i, count = Seq_length(ty->v.sym_ENUM.ids), value; 289 | getvalue(address, &value, ty->size); 290 | for (i = 0; i < count; i++) { 291 | sym_enum__ty e = Seq_get(ty->v.sym_ENUM.ids, i); 292 | if (e->value == value) { 293 | put("%s", e->id); 294 | return; 295 | } 296 | } 297 | put("(enum %s)%d", ty->v.sym_ENUM.tag, value); 298 | break; 299 | } 300 | case sym_VOID_enum: put("void"); break; 301 | #define xx(t,fmt) if (ty->size == sizeof (t)) do { t x; \ 302 | getvalue(address, &x, ty->size); put(fmt, x); return; } while (0) 303 | case sym_FLOAT_enum: 304 | xx(float,"%f"); 305 | xx(double, "%f"); 306 | xx(long double, "%Lg"); 307 | assert(0); 308 | case sym_INT_enum: 309 | xx(short, "%d"); 310 | xx(int, "%d"); 311 | xx(long, "%ld"); 312 | assert(ty->size == sizeof (char)); 313 | { 314 | char x; 315 | getvalue(address, &x, ty->size); 316 | if (x >= ' ' && x < 0177) 317 | put("'%c'", x); 318 | else 319 | put("'\\%03o'", x&0377); 320 | } 321 | break; 322 | case sym_UNSIGNED_enum: 323 | xx(unsigned char, "'%c'"); 324 | xx(unsigned short, "%u"); 325 | xx(unsigned int, "%u"); 326 | xx(unsigned long, "%lu"); 327 | assert(ty->size == sizeof (unsigned char)); 328 | { 329 | unsigned char x; 330 | getvalue(address, &x, ty->size); 331 | if (x >= ' ' && x < 0177) 332 | put("'%c'", x); 333 | else 334 | put("'\\%03o'", x&0377); 335 | } 336 | break; 337 | default:assert(0); 338 | } 339 | } 340 | 341 | static void prompt(void) { 342 | put("cdb> "); 343 | fflush(out); 344 | } 345 | 346 | static void printsym(const sym_symbol_ty sym, Nub_state_T *frame) { 347 | assert(sym); 348 | switch (sym->kind) { 349 | case sym_ENUMCONST_enum: 350 | put("%s=%d", sym->id, sym->v.sym_ENUMCONST.value); 351 | break; 352 | case sym_TYPEDEF_enum: 353 | put("%s is a typedef for ", sym->id); 354 | tput(sym->module, sym->type); 355 | break; 356 | case sym_STATIC_enum: case sym_GLOBAL_enum: { 357 | void *addr = _Sym_address(sym); 358 | put("%s@0x%x=", sym->id, addr); 359 | vput(sym->module, sym->type, addr); 360 | break; 361 | } 362 | case sym_PARAM_enum: { 363 | void *addr = frame->fp + sym->v.sym_PARAM.offset; 364 | put("%s@0x%x=", sym->id, addr); 365 | vput(sym->module, sym->type, addr); 366 | break; 367 | } 368 | case sym_LOCAL_enum: { 369 | void *addr = frame->fp + sym->v.sym_LOCAL.offset; 370 | put("%s@0x%x=", sym->id, addr); 371 | vput(sym->module, sym->type, addr); 372 | break; 373 | } 374 | default: assert(0); 375 | } 376 | } 377 | 378 | static void printparam(const sym_symbol_ty sym, Nub_state_T *frame) { 379 | if (sym->uplink) { 380 | const sym_symbol_ty next = _Sym_symbol(sym->module, sym->uplink); 381 | if (next->kind == sym_PARAM_enum) { 382 | printparam(next, frame); 383 | put(","); 384 | } 385 | } 386 | printsym(sym, frame); 387 | } 388 | 389 | static void printframe(int verbose, Nub_state_T *frame, int frameno) { 390 | put("%d\t%s(", frameno, frame->name); 391 | if (verbose > 0) { /* print parameters */ 392 | sym_symbol_ty sym = frame->context; 393 | for ( ; sym != NULL && sym->uplink > 0; sym = _Sym_symbol(sym->module, sym->uplink)) 394 | if (sym->kind == sym_PARAM_enum) { 395 | printparam(sym, frame); 396 | break; 397 | } else if (sym->kind == sym_STATIC_enum || sym->kind == sym_GLOBAL_enum) { 398 | put("void"); 399 | break; 400 | } 401 | } 402 | put(")\n"); 403 | if (verbose > 1) { /* print locals */ 404 | sym_symbol_ty sym = frame->context; 405 | for ( ; sym != NULL && sym->uplink > 0; sym = _Sym_symbol(sym->module, sym->uplink)) 406 | if (sym->kind == sym_LOCAL_enum) { 407 | put("\t"); 408 | printsym(sym, frame); 409 | put("\n"); 410 | } else 411 | break; 412 | } 413 | } 414 | 415 | static void moveto(int n) { 416 | Nub_state_T new; 417 | int m = _Nub_frame(n, &new); 418 | 419 | if (m == n) { 420 | printframe(1, &new, m); 421 | focus = new; 422 | frameno = m; 423 | } else 424 | put("?There is no frame %d\n", n); 425 | } 426 | 427 | static char *skipwhite(char *p) { 428 | while (*p && isspace(*p)) 429 | p++; 430 | return p; 431 | } 432 | 433 | static char *parse(char *line, Nub_coord_T *src) { 434 | char *p = line; 435 | static Nub_coord_T z; 436 | 437 | *src = z; 438 | if ((p = strchr(line, ':')) != NULL) { 439 | strncpy(src->file, line, p - line); 440 | src->file[p-line] = '\0'; 441 | p++; 442 | } else 443 | p = line; 444 | p = skipwhite(p); 445 | if (isdigit(*p)) 446 | for ( ; isdigit(*p); p++) 447 | src->y = 10*src->y + (*p - '0'); 448 | p = skipwhite(p); 449 | if (*p == '.') 450 | p++; 451 | p = skipwhite(p); 452 | if (isdigit(*p)) 453 | for ( ; isdigit(*p); p++) 454 | src->x = 10*src->x + (*p - '0'); 455 | return skipwhite(p); 456 | } 457 | 458 | static void setbp(int i, const Nub_coord_T *src, void *cl) { 459 | struct cdb_src *p = cl; 460 | 461 | p->n++; 462 | if (p->n == 1) 463 | p->first = *src; 464 | else if (p->n == 2) { 465 | put("Sweep and send one of the following commands:\n"); 466 | put("b %s:%d.%d\n", p->first.file, p->first.y, p->first.x); 467 | } 468 | if (p->n > 1) 469 | put("b %s:%d.%d\n", src->file, src->y, src->x); 470 | } 471 | 472 | static int equal(Nub_coord_T *s1, Nub_coord_T *s2) { 473 | return (s1->y == s2->y || s1->y == 0 || s2->y == 0) 474 | && (s1->x == s2->x || s1->x == 0 || s2->x == 0) 475 | && (s1->file[0] == 0 || s2->file[0] == 0 || strcmp(s1->file, s2->file) == 0); 476 | } 477 | 478 | static void b_cmd(char *line) { 479 | Nub_coord_T src; 480 | struct cdb_src z; 481 | 482 | if (*skipwhite(line) == 0) { 483 | int i; 484 | for (i = 0; i < nbpts; i++) 485 | put("r %s:%d.%d\n", bkpts[i].file, bkpts[i].y, bkpts[i].x); 486 | return; 487 | } 488 | if (*parse(line, &src)) { 489 | put("?Unrecognized coordinate: %s", line); 490 | return; 491 | } 492 | z.n = 0; 493 | _Nub_src(src, setbp, &z); 494 | if (z.n == 0) 495 | put("?There is no execution point at %s", line); 496 | else if (z.n == 1) { 497 | int i; 498 | for (i = 0; i < nbpts; i++) 499 | if (equal(&z.first, &bkpts[i])) { 500 | put("?There is already a breakpoint at %s:%d.%d\n", 501 | z.first.file, z.first.y, z.first.x); 502 | return; 503 | } 504 | if (nbpts < sizeof bkpts/sizeof bkpts[0]) { 505 | bkpts[nbpts++] = z.first; 506 | _Nub_set(z.first, onbreak); 507 | put("To remove this breakpoint, sweep and send the command:\n"); 508 | put("r %s:%d.%d\n", z.first.file, z.first.y, z.first.x); 509 | } else 510 | put("?Cannot set more than %d breakpoints\n", 511 | sizeof bkpts/sizeof bkpts[0]); 512 | } 513 | } 514 | 515 | static void r_cmd(char *line) { 516 | Nub_coord_T src; 517 | int i, j, n; 518 | char *p = skipwhite(line); 519 | 520 | if (*p) { 521 | p = parse(p, &src); 522 | if (*p) 523 | put("?Unrecognized coordinate: %s", line); 524 | 525 | } else if (brkpt == NULL) { 526 | put("?There is no current breakpoint\n"); 527 | return; 528 | } else { 529 | src = *brkpt; 530 | brkpt = NULL; 531 | } 532 | j = -1; 533 | for (i = n = 0; i < nbpts; i++) 534 | if (equal(&src, &bkpts[i])) { 535 | if (j < 0) 536 | j = i; 537 | n++; 538 | } 539 | if (n == 0) 540 | put("?There is no breakpoint at %s", line); 541 | else if (n == 1) { 542 | assert(j >= 0); 543 | _Nub_remove(bkpts[j]); 544 | bkpts[j] = bkpts[nbpts-1]; 545 | nbpts--; 546 | } else { 547 | put("Sweep and send any of the following commands:\n"); 548 | for (i = 0; i < nbpts; i++) 549 | if (equal(&src, &bkpts[i])) 550 | put("r %s:%d.%d\n", bkpts[i].file, bkpts[i].y, bkpts[i].x); 551 | } 552 | } 553 | 554 | static void v_cmd(const char *line) { 555 | Seq_T syms = _Sym_visible(focus.context); 556 | 557 | while (Seq_length(syms) > 0) { 558 | const sym_symbol_ty sym = Seq_remlo(syms); 559 | const sym_type_ty type = _Sym_type(sym->module, sym->type); 560 | if (type->kind != sym_FUNCTION_enum && sym->kind != sym_ENUM_enum 561 | && sym->kind != sym_TYPEDEF_enum) 562 | if (sym->kind == sym_STATIC_enum && sym->src->file != NULL) 563 | put("p %s:%s\n", sym->src->file, sym->id); 564 | else 565 | put("p %s\n", sym->id); 566 | } 567 | Seq_free(&syms); 568 | } 569 | 570 | static void p_cmd(char *line) { 571 | char *p = skipwhite(line); 572 | 573 | if (*p == 0) { 574 | v_cmd(p); 575 | return; 576 | } 577 | for ( ; *p; p = skipwhite(p)) { 578 | int n = 0; 579 | sym_symbol_ty sym; 580 | char *file = p, *name = p; 581 | while (*p && !isspace(*p) && *p != ':') 582 | p++; 583 | if (*p == ':' && p[1] && !isspace(p[1])) { 584 | *p++ = 0; 585 | name = p; 586 | while (*p && !isspace(*p)) 587 | p++; 588 | } else 589 | file = NULL; 590 | *p++ = 0; 591 | sym = _Sym_lookup(file, name, focus.context); 592 | if (sym != NULL) { 593 | if (sym->kind == sym_STATIC_enum && sym->src->file) 594 | put("%s:", sym->src->file); 595 | printsym(sym, &focus); 596 | put("\n"); 597 | n++; 598 | } else if (file != NULL) 599 | put("?Unknown identifier: %s:%s\n", file, name); 600 | else 601 | put("?Unknown identifier: %s\n", name); 602 | } 603 | } 604 | 605 | static void w_cmd(char *line) { 606 | Nub_state_T tmp; 607 | int i; 608 | 609 | for (i = 0; _Nub_frame(i, &tmp) == i; i++) { 610 | if (i == frameno) 611 | put("*"); 612 | printframe(1, &tmp, i); 613 | } 614 | } 615 | 616 | static void f_cmd(char *line) { 617 | char *p = line; 618 | 619 | if (isdigit(*p)) { 620 | Nub_state_T tmp; 621 | int n; 622 | for (n = 0; isdigit(*p); p++) 623 | n = 10*n + (*p - '0'); 624 | if (_Nub_frame(n, &tmp) != n) 625 | put("?There is no frame %d\n", n); 626 | else 627 | printframe(2, &tmp, n); 628 | } else 629 | printframe(2, &focus, frameno); 630 | } 631 | 632 | static void docmds(void) { 633 | char line[512]; 634 | static char help[] = 635 | "b list the breakpoints as r commands\n" 636 | "b [file:][line][.character]\n" 637 | " set a breakpoint at the specified source coordinate\n" 638 | "c continue execution\n" 639 | "d [n] move down the call stack 1 frame or n frames\n" 640 | "f [n] print everything about the current frame or about frame n\n" 641 | "h print this message\n" 642 | "m [n] move to frame 0 (the top frame) or to frame n\n" 643 | "p list the visible variables as p commands\n" 644 | "p {id} print the values of the listed identifiers\n" 645 | "q quit cdb and the target\n" 646 | "r remove the current breakpoint\n" 647 | "r [file:]line[.character]\n" 648 | " remove the breakpoint at the specified source coordinate\n" 649 | "u [n] move up the call stack 1 frame or n frames\n" 650 | "w display the call stack\n" 651 | "!cmd call the shell to execute cmd\n\n" 652 | "[X] means X is optional, {X} means 0 or more Xs\n" 653 | "$Id$" "\n"; 654 | 655 | prompt(); 656 | while (fgets(line, (int)sizeof line, in) != NULL) { 657 | int c, n; 658 | char *p = skipwhite(line); 659 | c = *p++; 660 | if (isalpha(c) && isalpha(*p)) 661 | put("?Unrecognized command: %s", line); 662 | else { 663 | p = skipwhite(p); 664 | switch (c) { 665 | case 0: break; 666 | case 'b': b_cmd(p); break; 667 | case 'f': f_cmd(p); break; 668 | case 'r': r_cmd(p); break; 669 | case 'p': p_cmd(p); break; 670 | case 'w': w_cmd(p); break; 671 | case 'm': 672 | for (n = 0; isdigit(*p); p++) 673 | n = 10*n + (*p - '0'); 674 | moveto(n); 675 | break; 676 | case 'd': 677 | case 'u': 678 | if (isdigit(*p)) { 679 | for (n = 0; isdigit(*p); p++) 680 | n = 10*n + (*p - '0'); 681 | } else 682 | n = 1; 683 | moveto(frameno + (c == 'u' ? -n : n)); 684 | break; 685 | case 'h': put("%s", help); break; 686 | case '!': system(p); break; 687 | case 'c': return; 688 | case 'q': exit(EXIT_FAILURE); 689 | case 't': { 690 | extern int trace; 691 | trace = atoi(p); 692 | break; 693 | } 694 | default: put("?Unrecognized command: %s", line); break; 695 | } 696 | } 697 | prompt(); 698 | } 699 | } 700 | 701 | static void whereis(Nub_state_T *state) { 702 | if (state->name[0]) 703 | put("in %.*s ", sizeof state->name, state->name); 704 | brkpt = &state->src; 705 | put("at %s:%d.%d\n", brkpt->file, brkpt->y, brkpt->x); 706 | focus = *state; 707 | frameno = 0; 708 | printframe(1, &focus, frameno); 709 | } 710 | 711 | static void onbreak(Nub_state_T state) { 712 | put("stopped "); 713 | whereis(&state); 714 | docmds(); 715 | } 716 | 717 | void _Cdb_startup(Nub_state_T state) { 718 | in = stdin; 719 | out = stderr; 720 | focus = state; 721 | frameno = -1; 722 | brkpt = NULL; 723 | _Sym_init(state.context); 724 | focus.context = NULL; 725 | docmds(); 726 | } 727 | 728 | void _Cdb_fault(Nub_state_T state) { 729 | put("fault "); 730 | whereis(&state); 731 | docmds(); 732 | exit(EXIT_FAILURE); 733 | } 734 | -------------------------------------------------------------------------------- /src/client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "comm.h" 8 | 9 | #ifdef unix 10 | static int WSAGetLastError(void) { 11 | return errno; 12 | } 13 | #endif 14 | 15 | static char rcsid[] = "$Id$"; 16 | 17 | static SOCKET in, out; 18 | 19 | static char *stringf(const char *fmt, ...) { 20 | static char buf[1024]; 21 | va_list ap; 22 | int n; 23 | 24 | va_start(ap, fmt); 25 | n = vsprintf(buf, fmt, ap); 26 | va_end(ap); 27 | return buf; 28 | } 29 | 30 | void _Nub_state(Nub_state_T *state, struct sframe *f) {} 31 | 32 | static void swtch(void); 33 | 34 | static void onbreak(Nub_state_T state) { 35 | Header_T msg = NUB_BREAK; 36 | 37 | assert(out); 38 | tracemesg("%s: sending %s\n", identity, mesgname(msg)); 39 | sendmesg(out, &msg, sizeof msg); 40 | sendmesg(out, &state, sizeof state); 41 | swtch(); 42 | } 43 | 44 | static void swtch(void) { 45 | for (;;) { 46 | Header_T msg; 47 | recvmesg(in, &msg, sizeof msg); 48 | tracemesg("%s: switching on %s\n", identity, mesgname(msg)); 49 | switch (msg) { 50 | case NUB_CONTINUE: return; 51 | case NUB_QUIT: out = 0; exit(EXIT_FAILURE); break; 52 | case NUB_FETCH: { 53 | int nbytes; 54 | struct nub_fetch args; 55 | recvmesg(in, &args, sizeof args); 56 | tracemesg("%s: _Nub_fetch(space=%d,address=%p,buf=NULL,nbytes=%d)\n", 57 | identity, args.space, args.address, args.nbytes); 58 | nbytes = _Nub_fetch(args.space, args.address, NULL, args.nbytes); 59 | sendmesg(out, &nbytes, sizeof nbytes); 60 | sendmesg(out, args.address, nbytes); 61 | break; 62 | } 63 | case NUB_STORE: { 64 | struct nub_store args; 65 | recvmesg(in, &args, sizeof args); 66 | tracemesg("%s: _Nub_store(space=%d,address=%p,buf=%p,nbytes=%d)\n", 67 | identity, args.space, args.address, args.buf, args.nbytes); 68 | args.nbytes = _Nub_store(args.space, args.address, args.buf, args.nbytes); 69 | sendmesg(out, &args.nbytes, sizeof args.nbytes); 70 | break; 71 | } 72 | case NUB_FRAME: { 73 | struct nub_frame args; 74 | recvmesg(in, &args, sizeof args); 75 | args.n = _Nub_frame(args.n, &args.state); 76 | sendmesg(out, &args, sizeof args); 77 | break; 78 | } 79 | default: assert(0); 80 | } 81 | } 82 | } 83 | 84 | static int connectto(const char *host, short port) { 85 | struct sockaddr_in server, client; 86 | struct hostent *hp; 87 | int len; 88 | unsigned long inaddr; 89 | 90 | in = socket(AF_INET, SOCK_STREAM, 0); 91 | if (in == SOCKET_ERROR) { 92 | perror(stringf("%s: socket (%d)", identity, WSAGetLastError())); 93 | return EXIT_FAILURE; 94 | } 95 | memset(&server, 0, sizeof server); 96 | server.sin_family = AF_INET; 97 | server.sin_port = htons(port); 98 | inaddr = inet_addr(host); 99 | if (inaddr != INADDR_NONE) 100 | memcpy(&server.sin_addr, &inaddr, sizeof inaddr); 101 | else if ((hp = gethostbyname(host)) != NULL) 102 | memcpy(&server.sin_addr, hp->h_addr, hp->h_length); 103 | else { 104 | fprintf(stderr, "%s: gethostbyname (%d)\n", identity, WSAGetLastError()); 105 | return EXIT_FAILURE; 106 | } 107 | if (connect(in, (struct sockaddr *)&server, sizeof server) != 0) { 108 | perror(stringf("%s: connect (%d)", identity, WSAGetLastError())); 109 | return EXIT_FAILURE; 110 | } 111 | len = sizeof client; 112 | if (getsockname(in, (struct sockaddr *)&client, &len) < 0) { 113 | perror(stringf("%s: getsockname (%d)", identity, WSAGetLastError())); 114 | return EXIT_FAILURE; 115 | } 116 | fprintf(stderr, "%s: connected on %s:%d ", identity, 117 | inet_ntoa(client.sin_addr), ntohs(client.sin_port)); 118 | fprintf(stderr, "to %s:%d\n", 119 | inet_ntoa(server.sin_addr), ntohs(server.sin_port)); 120 | out = in; 121 | return EXIT_SUCCESS; 122 | } 123 | 124 | static void cleanup(void) { 125 | if (out) { 126 | Header_T msg = NUB_QUIT; 127 | tracemesg("%s: sending %s\n", identity, mesgname(msg)); 128 | sendmesg(out, &msg, sizeof msg); 129 | closesocket(in); 130 | } 131 | #ifdef _WIN32 132 | WSACleanup(); 133 | #endif 134 | } 135 | 136 | void _Cdb_fault(Nub_state_T state) { 137 | Header_T msg = NUB_FAULT; 138 | 139 | if (out == 0) 140 | exit(EXIT_FAILURE); 141 | tracemesg("%s: sending %s\n", identity, mesgname(msg)); 142 | sendmesg(out, &msg, sizeof msg); 143 | sendmesg(out, &state, sizeof state); 144 | swtch(); 145 | } 146 | 147 | void _Cdb_startup(Nub_state_T state) { 148 | char *host, *s; 149 | short port = 9001; 150 | 151 | if ((host = getenv("DEBUGGER")) == NULL) 152 | return; 153 | s = strchr(host, ':'); 154 | if (s != NULL && s[1] != '\0') { 155 | *s = '\0'; 156 | port = atoi(s + 1); 157 | } 158 | #if _WIN32 159 | { 160 | WSADATA wsaData; 161 | int err = WSAStartup(MAKEWORD(2, 0), &wsaData); 162 | if (err != 0) { 163 | fprintf(stderr, "%s: WSAStartup (%d)", identity, err); 164 | return; 165 | } 166 | } 167 | #endif 168 | atexit(cleanup); 169 | if ((s = getenv("TRACE")) != NULL) 170 | trace = atoi(s); 171 | identity = "client"; 172 | if (connectto(host, port) == EXIT_SUCCESS) { /* start the nub */ 173 | Header_T msg = NUB_STARTUP; 174 | extern Nub_callback_T breakhandler; 175 | breakhandler = onbreak; 176 | tracemesg("%s: sending %s\n", identity, mesgname(msg)); 177 | sendmesg(out, &msg, sizeof msg); 178 | sendmesg(out, &state, sizeof state); 179 | swtch(); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/clientstub.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "nub.h" 5 | 6 | static char rcsid[] = "$Id$"; 7 | 8 | static void print(int i, const Nub_coord_T *src, void *cl) { 9 | static Nub_coord_T prev; 10 | 11 | if (strncmp(prev.file, src->file, sizeof prev.file) != 0) { 12 | fprintf(stderr, "\n%s:", src->file); 13 | prev = *src; 14 | } 15 | fprintf(stderr, "%d.%d ", src->y, src->x); 16 | } 17 | 18 | void _Cdb_startup(Nub_state_T state) { 19 | int i; 20 | struct module *m; 21 | 22 | for (i = 0; (m = _Nub_modules[i]) != NULL; i++) { 23 | int j, k; 24 | static Nub_coord_T z; 25 | fprintf(stderr, "module@%p\n", m); 26 | for (j = 1; m->files[j]; j++) 27 | fprintf(stderr, " %s", m->files[j]); 28 | if (m->globals != NULL) { 29 | const struct ssymbol *p; 30 | fprintf(stderr, ":"); 31 | for (p = m->globals; p != NULL; p= p->uplink) 32 | for (j = 1; m->files[j]; j++) 33 | if (strcmp(p->file, m->files[j]) == 0) { 34 | fprintf(stderr, " %s %p", p->name, p->type); 35 | break; 36 | } 37 | } else 38 | fprintf(stderr, "\n"); 39 | for (j = 1; m->files[j]; j++) { 40 | static Nub_coord_T z; 41 | strncpy(z.file, m->files[j], sizeof z.file); 42 | _Nub_src(z, print, NULL); 43 | fprintf(stderr, "\n"); 44 | } 45 | } 46 | } 47 | 48 | void _Cdb_fault(Nub_state_T state) { 49 | exit(EXIT_FAILURE); 50 | } 51 | -------------------------------------------------------------------------------- /src/comm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "comm.h" 6 | 7 | static char rcsid[] = "$Id$"; 8 | 9 | #ifdef unix 10 | extern int read(int, void *, int); 11 | extern int write(int, const void *, int); 12 | #else 13 | #define read(fd,buf,len) recv(fd,buf,len,0) 14 | #define write(fd,buf,len) send(fd,buf,len,0) 15 | #endif 16 | 17 | int trace = 0; 18 | const char *identity = ""; 19 | 20 | const char *mesgname(Header_T msg) { 21 | static char buf[120], *names[] = { 22 | #define xx(name) #name, 23 | messagecodes 24 | #undef xx 25 | }; 26 | if (msg >= 0 && msg < sizeof names/sizeof names[0]) 27 | return names[msg]; 28 | else 29 | sprintf(buf, "unknown message %d", msg); 30 | return buf; 31 | } 32 | 33 | void tracemesg(const char *fmt, ...) { 34 | if (trace) { 35 | va_list ap; 36 | va_start(ap, fmt); 37 | vfprintf(stderr, fmt, ap); 38 | va_end(ap); 39 | trace--; 40 | } 41 | } 42 | 43 | void recvmesg(SOCKET s, void *buf, int size) { 44 | int n; 45 | 46 | n = read(s, buf, size); 47 | tracemesg("%s: received %d bytes\n", identity, n); 48 | if (n != size) 49 | tracemesg("%s: **expected %d bytes\n", identity, size); 50 | assert(n == size); 51 | } 52 | 53 | void sendmesg(SOCKET s, const void *buf, int size) { 54 | int n; 55 | 56 | tracemesg("%s: sending %d bytes\n", identity, size); 57 | n = write(s, buf, size); 58 | if (n != size) 59 | tracemesg("%s: **expected %d bytes\n", identity, size); 60 | assert(n == size); 61 | } 62 | -------------------------------------------------------------------------------- /src/comm.h: -------------------------------------------------------------------------------- 1 | #ifndef COMM_INCLUDED 2 | #define COMM_INCLUDED 3 | #include "server.h" 4 | 5 | #ifdef _WIN32 6 | #include 7 | #else 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #ifndef INADDR_NONE 14 | #define INADDR_NONE (-1) 15 | #endif 16 | typedef int SOCKET; 17 | #define SOCKET_ERROR (-1) 18 | extern int close(int); 19 | #define closesocket(x) close(x) 20 | #endif 21 | 22 | extern int trace; 23 | extern const char *identity; 24 | 25 | extern const char *mesgname(Header_T msg); 26 | extern void tracemesg(const char *fmt, ...); 27 | extern void sendmesg(SOCKET s, const void *buf, int size); 28 | extern void recvmesg(SOCKET s, void *buf, int size); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/glue.h: -------------------------------------------------------------------------------- 1 | #ifndef GLUE_INCLUDED 2 | #define GLUE_INCLUDED 3 | 4 | /* $Id$ */ 5 | 6 | struct module { 7 | unsigned int uname; 8 | void **addresses; 9 | }; 10 | 11 | struct sframe { 12 | struct sframe *up, *down; 13 | int func; 14 | int module; 15 | int ip; 16 | }; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/inits.c: -------------------------------------------------------------------------------- 1 | void init(int argc, char *argv[]) { 2 | {extern void input_init(int, char *[]); input_init(argc, argv);} 3 | {extern void main_init(int, char *[]); main_init(argc, argv);} 4 | {extern void prof_init(int, char *[]); prof_init(argc, argv);} 5 | {extern void trace_init(int, char *[]); trace_init(argc, argv);} 6 | {extern void type_init(int, char *[]); type_init(argc, argv);} 7 | {extern void x86linux_init(int, char *[]); x86linux_init(argc, argv);} 8 | {extern void zstab_init(int, char *[]); zstab_init(argc, argv);} 9 | } 10 | extern int main(int, char *[]); 11 | -------------------------------------------------------------------------------- /src/nub.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "nub.h" 6 | 7 | static char rcsid[] = "$Id$"; 8 | 9 | struct sframe *_Nub_tos; 10 | 11 | static Nub_callback_T faulthandler; 12 | Nub_callback_T breakhandler; 13 | static int frameno; 14 | static struct sframe *fp; 15 | static struct { char *start, *end; } text, data, stack; 16 | 17 | static void movedown(void) { 18 | if (fp->down) { 19 | fp->down->up = fp; 20 | fp = fp->down; 21 | frameno++; 22 | } 23 | } 24 | 25 | static void moveup(void) { 26 | if (fp->up) { 27 | fp = fp->up; 28 | frameno--; 29 | } 30 | } 31 | 32 | /* update - update memory maps */ 33 | static void update(void) { 34 | char tos; 35 | #ifdef unix 36 | { 37 | extern char etext; 38 | extern void *sbrk(size_t); 39 | text.start = 0; 40 | text.end = &etext; 41 | data.start = &etext; 42 | data.end = sbrk(0); 43 | if (data.end == (char *)-1) 44 | data.end = data.start; 45 | stack.start = &tos; 46 | stack.end = (char *)-1; 47 | } 48 | #else 49 | text.start = 0; text.end = (char *)-1; 50 | data.start = 0; data.end = (char *)-1; 51 | stack.start = &tos; stack.end = (char *)-1; 52 | #endif 53 | } 54 | 55 | void _Nub_init(Nub_callback_T startup, Nub_callback_T fault) { 56 | Nub_state_T state; 57 | static Nub_state_T z; 58 | 59 | faulthandler = fault; 60 | fp = NULL; 61 | frameno = 0; 62 | state = z; 63 | state.context = _Nub_modules; 64 | state.fp = NULL; 65 | update(); 66 | startup(state); 67 | } 68 | 69 | void _Nub_bp(int index) { 70 | Nub_state_T state; 71 | 72 | if (!breakhandler) 73 | return; 74 | _Nub_tos->ip = index; 75 | fp = _Nub_tos; 76 | fp->up = NULL; 77 | state.fp = (char *)fp; 78 | frameno = 0; 79 | update(); 80 | breakhandler(state); 81 | } 82 | 83 | static int valid(const char *address, int nbytes) { 84 | #define xx(z) if (address >= z.start && address < z.end) \ 85 | return (unsigned)nbytes > z.end - address ? z.end - address : nbytes 86 | xx(stack); 87 | xx(data); 88 | xx(text); 89 | #undef xx 90 | return 0; 91 | } 92 | 93 | int _Nub_fetch(int space, const void *address, void *buf, int nbytes) { 94 | if (nbytes <= 0) 95 | return 0; 96 | nbytes = valid(address, nbytes); 97 | assert(nbytes >= 0); 98 | if (nbytes > 0 && buf) 99 | memcpy(buf, address, nbytes); 100 | return nbytes; 101 | } 102 | 103 | int _Nub_store(int space, void *address, const void *buf, int nbytes) { 104 | if (nbytes <= 0) 105 | return 0; 106 | if (space == 1) { /* write _Nub_bpflags[i] */ 107 | int i = (char *)address - (char *)NULL; 108 | assert(nbytes == 1); 109 | memcpy(&_Nub_bpflags[i], buf, nbytes); 110 | return nbytes; 111 | } 112 | nbytes = valid(address, nbytes); 113 | if (nbytes > 0 && buf) 114 | memcpy(address, buf, nbytes); 115 | return nbytes; 116 | } 117 | 118 | int _Nub_frame(int n, Nub_state_T *state) { 119 | if (fp == NULL) 120 | return -1; 121 | if (n == 0) { 122 | fp = _Nub_tos; 123 | frameno = 0; 124 | } else { 125 | while (n < frameno && fp->up) 126 | moveup(); 127 | while (n > frameno && fp->down) 128 | movedown(); 129 | } 130 | state->fp = (char *)fp; 131 | _Nub_state(state, NULL); 132 | return frameno; 133 | } 134 | 135 | int mAiN(int argc, char *argv[], char *envp[]) { 136 | extern int main(int, char *[], char *[]); 137 | extern void _Cdb_startup(Nub_state_T state), _Cdb_fault(Nub_state_T state); 138 | _Nub_init(_Cdb_startup, _Cdb_fault); 139 | return main(argc, argv, envp); 140 | } 141 | -------------------------------------------------------------------------------- /src/nub.h: -------------------------------------------------------------------------------- 1 | #ifndef NUB_INCLUDED 2 | #define NUB_INCLUDED 3 | #include "glue.h" 4 | 5 | /* $Id$ */ 6 | 7 | typedef struct { 8 | char file[32]; 9 | unsigned short x, y; 10 | } Nub_coord_T; 11 | 12 | typedef struct { 13 | char name[32]; 14 | Nub_coord_T src; 15 | char *fp; 16 | void *context; 17 | } Nub_state_T; 18 | 19 | typedef void (*Nub_callback_T)(Nub_state_T state); 20 | 21 | extern struct module *_Nub_modules[]; 22 | extern char _Nub_bpflags[]; 23 | extern struct sframe *_Nub_tos; 24 | extern void _Nub_state(Nub_state_T *state, struct sframe *f); 25 | 26 | extern void _Nub_init(Nub_callback_T startup, Nub_callback_T fault); 27 | extern void _Nub_bp(int index); 28 | extern void _Nub_src(Nub_coord_T src, 29 | void apply(int i, const Nub_coord_T *src, void *cl), void *cl); 30 | extern Nub_callback_T _Nub_set(Nub_coord_T src, Nub_callback_T onbreak); 31 | extern Nub_callback_T _Nub_remove(Nub_coord_T src); 32 | extern int _Nub_fetch(int space, const void *address, void *buf, int nbytes); 33 | extern int _Nub_store(int space, void *address, const void *buf, int nbytes); 34 | extern int _Nub_frame(int n, Nub_state_T *state); 35 | #endif 36 | -------------------------------------------------------------------------------- /src/nub2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "seq.h" 8 | #include "mem.h" 9 | #include "symtab.h" 10 | #include "nub.h" 11 | 12 | static char rcsid[] = "$Id$"; 13 | 14 | static int equal(Nub_coord_T *src, sym_coordinate_ty w) { 15 | /* 16 | Two coordinates are "equal" if their 17 | nondefault components are equal. 18 | */ 19 | return (src->y == 0 || src->y == w->y) 20 | && (src->x == 0 || src->x == w->x) 21 | && (src->file[0] == 0 || w->file && strcmp(src->file, w->file) == 0); 22 | } 23 | 24 | static int coord2bpaddr(Nub_coord_T *src, int *module) { 25 | int i, count = Seq_length(pickles); 26 | 27 | for (i = 0; i < count; i++) { 28 | sym_module_ty pickle = Seq_get(pickles, i); 29 | int j, n = Seq_length(pickle->spoints); 30 | for (j = 0; j < n; j++) { 31 | sym_spoint_ty s = Seq_get(pickle->spoints, j); 32 | if (equal(src, s->src)) { 33 | *module = pickle->uname; 34 | count = Seq_length(modules); 35 | for (i = 0; i < count; i++) { 36 | struct module *m = Seq_get(modules, i); 37 | if (pickle->uname == m->uname) 38 | return j; 39 | } 40 | assert(0); 41 | return 0; 42 | } 43 | } 44 | } 45 | assert(0); 46 | return 0; 47 | } 48 | 49 | void _Nub_state(Nub_state_T *state, struct sframe *fp) { 50 | struct sframe frame; 51 | sym_symbol_ty f; 52 | sym_module_ty m; 53 | sym_spoint_ty s; 54 | int n = _Nub_fetch(0, state->fp, fp ? fp : (fp = &frame), sizeof *fp); 55 | 56 | assert(n == sizeof *fp); 57 | f = _Sym_symbol(fp->module, fp->func); 58 | assert(f); 59 | strncpy(state->name, f->id, sizeof state->name); 60 | m = _Sym_module(fp->module); 61 | assert(m); 62 | s = Seq_get(m->spoints, fp->ip); 63 | assert(s); 64 | strncpy(state->src.file, s->src->file, sizeof state->src.file); 65 | state->src.x = s->src->x; state->src.y = s->src->y; 66 | state->context = _Sym_symbol(fp->module, s->tail); 67 | } 68 | 69 | struct bpoint { 70 | struct bpoint *link; 71 | int module, ip; 72 | } *bpoints; 73 | extern Nub_callback_T breakhandler; 74 | static Nub_callback_T bphandler; 75 | 76 | static void onbp(Nub_state_T state) { 77 | struct sframe frame; 78 | struct bpoint *b; 79 | 80 | _Nub_state(&state, &frame); 81 | for (b = bpoints; b != NULL; b = b->link) 82 | if (b->ip == frame.ip && b->module == frame.module) { 83 | (*bphandler)(state); 84 | break; 85 | } 86 | } 87 | 88 | Nub_callback_T _Nub_set(Nub_coord_T src, Nub_callback_T onbreak) { 89 | Nub_callback_T prev = bphandler; 90 | struct bpoint *b; 91 | int module, ip = coord2bpaddr(&src, &module); 92 | char flag = 1; 93 | int n = _Nub_store(1, (char *)NULL + ip, &flag, 1); 94 | 95 | assert(n == 1); 96 | for (b = bpoints; b != NULL; b = b->link) 97 | if (b->ip == ip && b->module == module) 98 | break; 99 | if (b == NULL) { 100 | NEW(b); 101 | b->link = bpoints; 102 | bpoints = b; 103 | } 104 | b->ip = ip; 105 | b->module = module; 106 | bphandler = onbreak; 107 | breakhandler = onbp; 108 | return prev; 109 | } 110 | 111 | Nub_callback_T _Nub_remove(Nub_coord_T src) { 112 | int count = 0, module, ip = coord2bpaddr(&src, &module); 113 | struct bpoint *b, **prev = &bpoints; 114 | 115 | for (b = bpoints; b != NULL; b = *prev) 116 | if (b->ip == ip && b->module == module) { 117 | *prev = b->link; 118 | FREE(b); 119 | } else { 120 | if (b->ip == ip) 121 | count++; 122 | prev = &b->link; 123 | } 124 | if (count == 0) { 125 | char flag = 0; 126 | int n = _Nub_store(1, (char *)NULL + ip, &flag, 1); 127 | assert(n == 1); 128 | } 129 | return bphandler; 130 | } 131 | 132 | void _Nub_src(Nub_coord_T src, 133 | void apply(int i, const Nub_coord_T *src, void *cl), void *cl) { 134 | int i, k = 0, count = Seq_length(pickles); 135 | 136 | for (i = 0; i < count; i++) { 137 | sym_module_ty pickle = Seq_get(pickles, i); 138 | int j, n = Seq_length(pickle->spoints); 139 | for (j = 0; j < n; j++) { 140 | sym_spoint_ty s = Seq_get(pickle->spoints, j); 141 | if (equal(&src, s->src)) { 142 | Nub_coord_T z; 143 | strncpy(z.file, s->src->file, sizeof z.file); 144 | z.x = s->src->x; z.y = s->src->y; 145 | apply(k++, &z, cl); 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/prelink.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # $Id$ 4 | 5 | # prelink -o file files... 6 | # generates list of module pointers in the given object files 7 | # on the standard output as a C program 8 | 9 | # set -x 10 | case "$1" in 11 | -o) ofile=$2; shift; shift ;; 12 | *) ofile=/tmp/$$.o ;; 13 | esac 14 | cfile=`expr "$ofile" : '\(.*\.\)'`c 15 | for i 16 | do 17 | case "$i" in 18 | -*|*.a|*.lib) ;; 19 | *) files="$files $i" ;; 20 | esac 21 | done 22 | nm $files | awk ' 23 | /_module_V/ { 24 | if (match($0, /_module_V[0-9a-f]*/)) { 25 | m=substr($0, RSTART, RLENGTH) 26 | if (!seen[m]) { 27 | printf "extern struct module %s;\n", m 28 | seen[m] = 1 29 | } } 30 | } 31 | /_spoints_V/ { 32 | if (match($0, /_[0-9]+/)) { 33 | n = substr($0, RSTART+1, RLENGTH-1) 34 | if (max < n) max = n 35 | } } 36 | END { 37 | print "struct module *_Nub_modules[] = {" 38 | for (m in seen) printf "\t&%s,\n", m 39 | printf "\t0\n};\n" 40 | printf "char _Nub_bpflags[%d];\n", max + 1 41 | }' >$cfile 42 | lcc -c -o "$ofile" $cfile 43 | -------------------------------------------------------------------------------- /src/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "fmt.h" 8 | #include "comm.h" 9 | 10 | static char rcsid[] = "$Id$"; 11 | 12 | static SOCKET in, out; 13 | Nub_callback_T breakhandler; 14 | 15 | static void sendout(int op, const void *buf, int size) { 16 | Header_T msg; 17 | 18 | msg = op; 19 | tracemesg("%s: sending %s\n", identity, mesgname(msg)); 20 | sendmesg(out, &msg, sizeof msg); 21 | if (size > 0) { 22 | assert(buf); 23 | sendmesg(out, buf, size); 24 | } 25 | } 26 | 27 | int _Nub_frame(int n, Nub_state_T *state) { 28 | struct nub_frame args; 29 | 30 | args.n = n; 31 | sendout(NUB_FRAME, &args, sizeof args); 32 | recvmesg(in, &args, sizeof args); 33 | if (args.n >= 0) 34 | memcpy(state, &args.state, sizeof args.state); 35 | _Nub_state(state, NULL); 36 | return args.n; 37 | } 38 | 39 | void _Nub_init(Nub_callback_T startup, Nub_callback_T fault) { 40 | Header_T msg; 41 | Nub_state_T state; 42 | 43 | recvmesg(in, &msg, sizeof msg); 44 | assert(msg == NUB_STARTUP); 45 | recvmesg(in, &state, sizeof state); 46 | startup(state); 47 | for (;;) { 48 | sendout(NUB_CONTINUE, NULL, 0); 49 | recvmesg(in, &msg, sizeof msg); 50 | tracemesg("%s: switching on %s\n", identity, mesgname(msg)); 51 | switch (msg) { 52 | case NUB_BREAK: 53 | recvmesg(in, &state, sizeof state); 54 | (*breakhandler)(state); 55 | break; 56 | case NUB_FAULT: 57 | recvmesg(in, &state, sizeof state); 58 | _Nub_state(&state, NULL); 59 | fault(state); 60 | break; 61 | case NUB_QUIT: return; 62 | default: assert(0); 63 | } 64 | } 65 | } 66 | 67 | int _Nub_fetch(int space, const void *address, void *buf, int nbytes) { 68 | struct nub_fetch args; 69 | 70 | args.space = space; 71 | args.address = address; 72 | args.nbytes = nbytes; 73 | tracemesg("%s: _Nub_fetch(space=%d,address=%p,buf=%p,nbytes=%d)\n", 74 | identity, space, address, buf, nbytes); 75 | sendout(NUB_FETCH, &args, sizeof args); 76 | recvmesg(in, &args.nbytes, sizeof args.nbytes); 77 | recvmesg(in, buf, args.nbytes); 78 | return args.nbytes; 79 | } 80 | 81 | int _Nub_store(int space, void *address, const void *buf, int nbytes) { 82 | struct nub_store args; 83 | 84 | args.space = space; 85 | args.address = address; 86 | args.nbytes = nbytes; 87 | assert(nbytes <= sizeof args.buf); 88 | memcpy(args.buf, buf, nbytes); 89 | tracemesg("%s: _Nub_store(space=%d,address=%p,buf=%p,nbytes=%d)\n", 90 | identity, space, address, buf, nbytes); 91 | sendout(NUB_STORE, &args, sizeof args); 92 | recvmesg(in, &args.nbytes, sizeof args.nbytes); 93 | return args.nbytes; 94 | } 95 | 96 | extern void _Cdb_startup(Nub_state_T state), _Cdb_fault(Nub_state_T state); 97 | 98 | static void cleanup(void) { 99 | if (out) { 100 | sendout(NUB_QUIT, NULL, 0); 101 | closesocket(out); 102 | } 103 | #ifdef _WIN32 104 | WSACleanup(); 105 | #endif 106 | } 107 | 108 | #ifdef unix 109 | static int WSAGetLastError(void) { 110 | return errno; 111 | } 112 | #endif 113 | 114 | static int server(short port) { 115 | struct sockaddr_in server; 116 | SOCKET fd = socket(AF_INET, SOCK_STREAM, 0); 117 | 118 | if (fd == SOCKET_ERROR) { 119 | perror(Fmt_string("%s: socket (%d)", identity, WSAGetLastError())); 120 | return EXIT_FAILURE; 121 | } 122 | memset(&server, 0, sizeof server); 123 | server.sin_family = AF_INET; 124 | server.sin_addr.s_addr = htonl(INADDR_ANY); 125 | server.sin_port = htons(port); 126 | if (bind(fd, (struct sockaddr *)&server, sizeof server) != 0) { 127 | perror(Fmt_string("%s: bind (%d)", identity, WSAGetLastError())); 128 | return EXIT_FAILURE; 129 | } 130 | printf("%s listening on %s:%d\n", identity, inet_ntoa(server.sin_addr), ntohs(server.sin_port)); 131 | listen(fd, 5); 132 | for (;;) { 133 | struct sockaddr_in client; 134 | int len = sizeof client; 135 | in = accept(fd, (struct sockaddr *)&client, &len); 136 | if (in == SOCKET_ERROR) { 137 | perror(Fmt_string("%s: accept (%d)", identity, WSAGetLastError())); 138 | return EXIT_FAILURE; 139 | } 140 | printf("%s: now serving %s:%d\n", identity, inet_ntoa(client.sin_addr), ntohs(client.sin_port)); 141 | out = in; 142 | _Nub_init(_Cdb_startup, _Cdb_fault); 143 | out = 0; 144 | closesocket(in); 145 | printf("%s: disconnected\n", identity); 146 | } 147 | } 148 | 149 | int main(int argc, char *argv[]) { 150 | short port = 9001; 151 | int i; 152 | char *s; 153 | 154 | if ((s = getenv("TRACE")) != NULL) 155 | trace = atoi(s); 156 | identity = argv[0]; 157 | #if _WIN32 158 | { 159 | WSADATA wsaData; 160 | int err = WSAStartup(MAKEWORD(2, 0), &wsaData); 161 | if (err != 0) { 162 | fprintf(stderr, "%s: WSAStartup (%d)", identity, err); 163 | return EXIT_FAILURE; 164 | } 165 | } 166 | #endif 167 | atexit(cleanup); 168 | for (i = 1; i < argc; i++) 169 | if (isdigit(*argv[i])) 170 | port = atoi(argv[i]); 171 | else if (strncmp(argv[i], "-trace=", 7) == 0) 172 | trace = atoi(argv[i] + 7); 173 | return server(port); 174 | } 175 | -------------------------------------------------------------------------------- /src/server.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_INCLUDED 2 | #define SERVER_INCLUDED 3 | #include "nub.h" 4 | 5 | /* $Id$ */ 6 | 7 | #define messagecodes \ 8 | xx(NUB_CONTINUE) \ 9 | xx(NUB_QUIT) \ 10 | xx(NUB_STARTUP) \ 11 | xx(NUB_BREAK) \ 12 | xx(NUB_FAULT) \ 13 | xx(NUB_FETCH) \ 14 | xx(NUB_STORE) \ 15 | xx(NUB_FRAME) \ 16 | xx(NUB_SRC) 17 | 18 | typedef enum { /* messages */ 19 | #define xx(name) name, 20 | messagecodes 21 | #undef xx 22 | } Header_T; 23 | 24 | struct nub_fetch { 25 | int space; 26 | const void *address; 27 | int nbytes; 28 | }; 29 | 30 | struct nub_store { 31 | int space; 32 | void *address; 33 | int nbytes; 34 | char buf[1024]; 35 | }; 36 | 37 | struct nub_frame { 38 | int n; 39 | Nub_state_T state; 40 | }; 41 | #endif 42 | -------------------------------------------------------------------------------- /src/stab.c: -------------------------------------------------------------------------------- 1 | #define NDEBUG 2 | #include "c.h" 3 | #undef NDEBUG 4 | #include "pkl-int.h" 5 | #include "glue.h" 6 | #include "sym.h" 7 | #include 8 | #include 9 | #include 10 | #include "table.h" 11 | #include "seq.h" 12 | 13 | static char rcsid[] = "$Id$"; 14 | 15 | static char *leader; 16 | static sym_module_ty pickle; 17 | static Symbol module; 18 | static unsigned uname; 19 | static Symbol nub_bp; 20 | static Symbol nub_bpflags; 21 | static Symbol nub_tos; 22 | static Symbol tos; 23 | static Seq_T locals; 24 | static Seq_T statics; 25 | static Table_T uidTable; 26 | static int maxalign; 27 | 28 | static int typeuid(const Type); 29 | static int symboluid(const Symbol); 30 | 31 | char *string(const char *str) { 32 | return (char *)Atom_string(str); 33 | } 34 | 35 | char *stringd(long n) { 36 | return (char *)Atom_int(n); 37 | } 38 | 39 | char *stringn(const char *str, int len) { 40 | return (char *)Atom_new(str, len); 41 | } 42 | 43 | /* comment - emits an assembly language comment */ 44 | static void comment(char *fmt, ...) { 45 | va_list ap; 46 | 47 | print(leader); 48 | va_start(ap, fmt); 49 | vfprint(stdout, NULL, fmt, ap); 50 | va_end(ap); 51 | } 52 | 53 | /* pad - emits padding, when necessary, and returns updated location counter */ 54 | static int pad(int align, int lc) { 55 | assert(align); 56 | if (lc%align) { 57 | (*IR->space)(align - lc%align); 58 | lc = roundup(lc, align); 59 | } 60 | if (align > maxalign) 61 | maxalign = align; 62 | return lc; 63 | } 64 | 65 | /* emit_value - emits an initialization for the type given by ty */ 66 | static int emit_value(int lc, Type ty, ...) { 67 | Value v; 68 | va_list ap; 69 | 70 | va_start(ap, ty); 71 | if (lc == 0) 72 | maxalign = 0; 73 | lc = pad(ty->align, lc); 74 | switch (ty->op) { 75 | case INT: v.i = va_arg(ap, long); break; 76 | case UNSIGNED: v.u = va_arg(ap, unsigned long); break; 77 | case FLOAT: v.d = va_arg(ap, long double); break; 78 | case POINTER: 79 | defpointer(va_arg(ap, Symbol)); 80 | return lc + ty->size; 81 | default: assert(0); 82 | } 83 | va_end(ap); 84 | (*IR->defconst)(ty->op, ty->size, v); 85 | return lc + ty->size; 86 | } 87 | 88 | /* typeuid - returns ty's uid, adding the type, if necessary */ 89 | static int typeuid(const Type ty) { 90 | sym_type_ty type; 91 | 92 | if (ty->x.typeno != 0) 93 | return ty->x.typeno; 94 | ty->x.typeno = pickle->nuids++; 95 | switch (ty->op) { 96 | #define xx(op) case op: type = sym_##op(ty->size, ty->align); break 97 | xx(INT); 98 | xx(UNSIGNED); 99 | xx(FLOAT); 100 | xx(VOID); 101 | #undef xx 102 | #define xx(op) case op: type = sym_##op(ty->size, ty->align, typeuid(ty->type)); break 103 | xx(POINTER); 104 | xx(CONST); 105 | xx(VOLATILE); 106 | #undef xx 107 | case ARRAY: 108 | type = sym_ARRAY(ty->size, ty->align, typeuid(ty->type), 0); 109 | if (ty->type->size > 0) 110 | type->v.sym_ARRAY.nelems = ty->size/ty->type->size; 111 | break; 112 | case CONST+VOLATILE: 113 | type = sym_CONST(ty->size, ty->align, typeuid(ty->type)); 114 | break; 115 | case ENUM: { 116 | list_ty ids = Seq_new(0); 117 | int i; 118 | for (i = 0; ty->u.sym->u.idlist[i] != NULL; i++) 119 | Seq_addhi(ids, sym_enum_(ty->u.sym->u.idlist[i]->name, 120 | ty->u.sym->u.idlist[i]->u.value)); 121 | assert(i > 0); 122 | type = sym_ENUM(ty->size, ty->align, ty->u.sym->name, ids); 123 | break; 124 | } 125 | case STRUCT: case UNION: { 126 | list_ty fields = Seq_new(0); 127 | Field p = fieldlist(ty); 128 | for ( ; p != NULL; p = p->link) 129 | Seq_addhi(fields, sym_field(p->name, typeuid(p->type), p->offset, p->bitsize, p->lsb)); 130 | if (ty->op == STRUCT) 131 | type = sym_STRUCT(ty->size, ty->align, ty->u.sym->name, fields); 132 | else 133 | type = sym_UNION (ty->size, ty->align, ty->u.sym->name, fields); 134 | break; 135 | } 136 | case FUNCTION: { 137 | list_ty formals = Seq_new(0); 138 | if (ty->u.f.proto != NULL && ty->u.f.proto[0] != NULL) { 139 | int i; 140 | for (i = 0; ty->u.f.proto[i] != NULL; i++) 141 | Seq_addhi(formals, to_generic_int(typeuid(ty->u.f.proto[i]))); 142 | } else if (ty->u.f.proto != NULL && ty->u.f.proto[0] == NULL) 143 | Seq_addhi(formals, to_generic_int(typeuid(voidtype))); 144 | type = sym_FUNCTION(ty->size, ty->align, typeuid(ty->type), formals); 145 | break; 146 | } 147 | default: assert(0); 148 | } 149 | Seq_addhi(pickle->items, sym_Type(ty->x.typeno, type)); 150 | return ty->x.typeno; 151 | } 152 | 153 | /* up - returns p's non-external ancestor */ 154 | static Symbol up(Symbol p) { 155 | while (p != NULL && p->defined == 0 156 | && (p->sclass == EXTERN || isfunc(p->type) && p->sclass == AUTO)) 157 | p = p->up; 158 | return p; 159 | } 160 | 161 | /* symboluid - returns sym's uid, adding the symbol, if necessary */ 162 | static int symboluid(const Symbol p) { 163 | int uid; 164 | sym_symbol_ty sym; 165 | 166 | if (p == NULL) 167 | return 0; 168 | sym = Table_get(uidTable, p); 169 | if (sym != NULL) 170 | return sym->uid; 171 | uid = pickle->nuids++; 172 | switch (p->sclass) { 173 | case ENUM: 174 | sym = sym_ENUMCONST(p->name, uid, uname, NULL, 0, 0, 175 | p->u.value); 176 | sym->type = typeuid(inttype); 177 | break; 178 | case TYPEDEF: 179 | sym = sym_TYPEDEF(p->name, uid, uname, NULL, 0, 0); 180 | sym->type = typeuid(p->type); 181 | break; 182 | default: 183 | if (p->sclass == STATIC) { 184 | sym = sym_STATIC(p->name, uid, uname, NULL, 0, 0, 185 | Seq_length(statics)); 186 | Seq_addhi(statics, p); 187 | } else if (p->scope == GLOBAL || p->sclass == EXTERN) { 188 | sym = sym_GLOBAL(p->name, uid, uname, NULL, 0, 0, 189 | Seq_length(statics)); 190 | Seq_addhi(statics, p); 191 | } else if (p->scope == PARAM) 192 | sym = sym_PARAM(p->name, uid, uname, NULL, 0, 0, 193 | p->x.offset); 194 | else { 195 | assert(p->scope >= LOCAL); 196 | sym = sym_LOCAL(p->name, uid, uname, NULL, 0, 0, 197 | p->x.offset); 198 | } 199 | sym->type = typeuid(p->type); 200 | } 201 | Table_put(uidTable, p, sym); 202 | Seq_addhi(pickle->items, sym_Symbol(uid, sym)); 203 | sym->src = sym_coordinate(p->src.file ? p->src.file : string(""), p->src.x, p->src.y); 204 | sym->uplink = symboluid(up(p->up)); 205 | return sym->uid; 206 | } 207 | 208 | /* stabend - emits the symbol table */ 209 | static void stabend(Coordinate *cp, Symbol symroot, Coordinate *cpp[], Symbol sp[], Symbol *ignore) { 210 | Symbol addresses; 211 | int naddresses, nmodule; 212 | 213 | { /* annotate top-level symbols */ 214 | Symbol p; 215 | for (p = symroot; p != NULL; p = up(p->up)) 216 | symboluid(p); 217 | pickle->globals = symboluid(symroot); 218 | } 219 | { /* emit addresses of top-level and static symbols */ 220 | int i, lc = 0, count = Seq_length(statics); 221 | addresses = genident(STATIC, array(voidptype, 1, 0), GLOBAL); 222 | comment("addresses:\n"); 223 | defglobal(addresses, LIT); 224 | for (i = 0; i < count; i++) { 225 | Symbol p = Seq_get(statics, i); 226 | lc = emit_value(lc, voidptype, p); 227 | } 228 | lc = pad(maxalign, lc); 229 | naddresses = lc; 230 | Seq_free(&statics); 231 | } 232 | { /* emit bp count as an alias for the module */ 233 | Symbol spoints = mksymbol(AUTO, 234 | stringf("_spoints_V%x_%d", uname, Seq_length(pickle->spoints)), 235 | array(unsignedtype, 0, 0)); 236 | spoints->generated = 1; 237 | defglobal(spoints, LIT); 238 | } 239 | { /* emit module */ 240 | int lc; 241 | comment("module:\n"); 242 | defglobal(module, LIT); 243 | lc = emit_value( 0, unsignedtype, (unsigned long)uname); 244 | lc = emit_value(lc, voidptype, addresses); 245 | lc = pad(maxalign, lc); 246 | nmodule = lc; 247 | } 248 | Seq_free(&locals); 249 | #define printit(x) fprintf(stderr, "%7d " #x "\n", n##x); total += n##x 250 | { 251 | int total = 0; 252 | printit(addresses); 253 | printit(module); 254 | fprintf(stderr, "%7d bytes total\n", total); 255 | } 256 | #undef printit 257 | { /* complete and write symbol-table pickle */ 258 | FILE *f = fopen(stringf("%d.pickle", uname), "wb"); 259 | sym_write_module(pickle, f); 260 | fclose(f); 261 | } 262 | } 263 | 264 | /* tail - returns the current tail of the symbol table */ 265 | static int tail(void) { 266 | Symbol p = allsymbols(identifiers); 267 | 268 | p = up(p); 269 | if (p) 270 | return symboluid(p); 271 | else 272 | return 0; 273 | } 274 | 275 | /* point_hook - called at each execution point */ 276 | static void point_hook(void *cl, Coordinate *cp, Tree *e) { 277 | Tree t; 278 | 279 | /* 280 | add breakpoint test to *e: 281 | (_Nub_bpflags[i] != 0 && _Nub_bp(i), *e) 282 | */ 283 | t = tree(AND, voidtype, 284 | (*optree[NEQ])(NE, 285 | rvalue((*optree['+'])(ADD, 286 | pointer(idtree(nub_bpflags)), 287 | cnsttree(inttype, Seq_length(pickle->spoints)))), 288 | cnsttree(inttype, 0L)), 289 | vcall(nub_bp, voidtype, cnsttree(inttype, Seq_length(pickle->spoints)), NULL)); 290 | if (*e) 291 | *e = tree(RIGHT, (*e)->type, t, *e); 292 | else 293 | *e = t; 294 | Seq_addhi(pickle->spoints, 295 | sym_spoint(sym_coordinate(cp->file ? cp->file : string(""), cp->x, cp->y), tail())); 296 | } 297 | 298 | /* setoffset - remember p for later adjustment of its offset */ 299 | static void setoffset(Symbol p, void *tos) { 300 | Seq_addhi(locals, p); 301 | p->addressed = 1; 302 | } 303 | 304 | /* entry_hook - called an function entry */ 305 | static void entry_hook(void *cl, Symbol cfunc) { 306 | static int nfuncs; 307 | Type ty; 308 | 309 | /* 310 | Simulate the declaration of an sframe structure, 311 | but without the tag. 312 | */ 313 | ty = newstruct(STRUCT, ""); 314 | #define addfield(name,t) \ 315 | ty->size = roundup(ty->size, t->align);\ 316 | if (ty->align < t->align) ty->align = t->align; \ 317 | newfield(string(name), ty, t)->offset = ty->size; \ 318 | ty->size += t->size 319 | addfield("up", voidptype); 320 | addfield("down", voidptype); 321 | addfield("func", inttype); 322 | addfield("module",inttype); 323 | addfield("ip", inttype); 324 | #undef addfield 325 | ty->size = roundup(ty->size, ty->align); 326 | ty->u.sym->defined = 1; 327 | ty->u.sym->generated = 1; 328 | tos = genident(AUTO, ty, LOCAL); 329 | addlocal(tos); 330 | tos->defined = 1; 331 | /* 332 | Generated the assignments to the shadow 333 | frame fields. 334 | */ 335 | #define set(name,e) walk(asgntree(ASGN,field(lvalue(idtree(tos)),string(#name)),(e)),0,0) 336 | set(down, idtree(nub_tos)); 337 | set(func, cnsttree(inttype, symboluid(cfunc))); 338 | set(module, cnsttree(inttype, uname)); 339 | #undef set 340 | walk(asgn(nub_tos, lvalue(idtree(tos))), 0, 0); 341 | foreach(identifiers, PARAM, setoffset, tos); 342 | } 343 | 344 | /* block_hook - called at block entry */ 345 | static void block_hook(void *cl, Symbol *p) { 346 | while (*p) 347 | setoffset(*p++, tos); 348 | } 349 | 350 | /* stabfend - called at end end of compiling a function */ 351 | static void stabfend(Symbol cfunc, int lineno) { 352 | int count = Seq_length(locals); 353 | 354 | for ( ; count > 0; count--) { 355 | Symbol p = Seq_remlo(locals); 356 | sym_symbol_ty sym = Table_get(uidTable, p); 357 | p->x.offset -= tos->x.offset; 358 | assert(sym); 359 | switch (sym->kind) { 360 | case sym_LOCAL_enum: sym->v.sym_LOCAL.offset = p->x.offset; break; 361 | case sym_PARAM_enum: sym->v.sym_PARAM.offset = p->x.offset; break; 362 | default: assert(0); 363 | } 364 | } 365 | tos = NULL; 366 | } 367 | 368 | /* return_hook - called at return statements. 369 | For return *e, return_hook changes the expression to be the equivalent of 370 | the C expression 371 | 372 | (_Nub_tos = tos.down, *e) 373 | */ 374 | static void return_hook(void *cl, Symbol cfunc, Tree *e) { 375 | walk(asgn(nub_tos, field(lvalue(idtree(tos)), string("down"))), 0, 0); 376 | } 377 | 378 | /* call_hook - called at function calls. 379 | If *e is a call, call_hook changes the expression to the equivalent of 380 | the C expression 381 | 382 | (tos.ip = i, *e) 383 | 384 | where i is the stopping point index for the execution point of the 385 | expression in which the call appears. 386 | */ 387 | static void call_hook(void *cl, Coordinate *cp, Tree *e) { 388 | assert(*e); 389 | *e = tree(RIGHT, (*e)->type, 390 | asgntree(ASGN, 391 | field(lvalue(idtree(tos)), string("ip")), 392 | cnsttree(inttype, Seq_length(pickle->spoints))), 393 | *e); 394 | } 395 | 396 | /* stabinit - initialize for symbol table emission */ 397 | static void stabinit(char *file, int argc, char *argv[]) { 398 | extern Interface sparcIR, solarisIR, x86IR; 399 | extern int getpid(void); 400 | 401 | if (IR == &solarisIR || IR == &sparcIR) 402 | leader = "!"; 403 | else if (IR == &x86IR) 404 | leader = ";"; 405 | else 406 | leader = " #"; /* it's a MIPS or ALPHA */ 407 | uname = time(NULL)<<7|getpid(); 408 | pickle = sym_module(file ? file : string(""), uname, 1, Seq_new(0), 0, Seq_new(0)); 409 | locals = Seq_new(0); 410 | statics = Seq_new(0); 411 | uidTable = Table_new(0, 0, 0); 412 | module = mksymbol(AUTO, stringf("_module_V%x", uname), array(unsignedtype, 0, 0)); 413 | module->generated = 1; 414 | nub_bpflags = mksymbol(EXTERN, "_Nub_bpflags", array(chartype, 1, 0)); 415 | nub_bpflags->defined = 0; 416 | attach((Apply) entry_hook, NULL, &events.entry); 417 | attach((Apply) block_hook, NULL, &events.blockentry); 418 | attach((Apply) point_hook, NULL, &events.points); 419 | attach((Apply) call_hook, NULL, &events.calls); 420 | attach((Apply)return_hook, NULL, &events.returns); 421 | nub_bp = mksymbol(EXTERN, "_Nub_bp", ftype(voidtype, inttype)); 422 | nub_bp->defined = 0; 423 | nub_tos = mksymbol(EXTERN, "_Nub_tos", voidptype); 424 | nub_tos->defined = 0; 425 | } 426 | 427 | void zstab_init(int argc, char *argv[]) { 428 | int i; 429 | static int inited; 430 | 431 | if (inited) 432 | return; 433 | assert(IR); 434 | inited = 1; 435 | for (i = 1; i < argc; i++) 436 | if (strcmp(argv[i], "-v") == 0) 437 | fprint(stderr, "%s %s\n", argv[0], rcsid); 438 | else if (strcmp(argv[i], "-g4") == 0) { 439 | IR->stabinit = stabinit; 440 | IR->stabend = stabend; 441 | IR->stabblock = 0; 442 | IR->stabfend = stabfend; 443 | IR->stabline = 0; 444 | IR->stabsym = 0; 445 | IR->stabtype = 0; 446 | glevel = 4; 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /src/sym.asdl: -------------------------------------------------------------------------------- 1 | -- cdb symbol tables 2 | -- $Id$ 3 | module sym { 4 | 5 | module = (identifier file,int uname,int nuids,item* items,int globals,spoint* spoints) 6 | 7 | spoint = (coordinate src,int tail) 8 | 9 | item = Symbol(symbol symbol) 10 | | Type(type type) 11 | attributes(int uid) 12 | 13 | coordinate = (identifier file,int x,int y) 14 | 15 | symbol = STATIC(int index) 16 | | GLOBAL(int index) 17 | | TYPEDEF 18 | | LOCAL(int offset) 19 | | PARAM(int offset) 20 | | ENUMCONST(int value) 21 | attributes(identifier id,int uid,int module,coordinate src, 22 | int type,int uplink) 23 | 24 | field = (identifier id,int type,int offset,int bitsize,int lsb) 25 | 26 | enum = (identifier id,int value) 27 | 28 | type = INT 29 | | UNSIGNED 30 | | FLOAT 31 | | VOID 32 | | POINTER(int type) 33 | | ENUM(identifier tag,enum* ids) 34 | | STRUCT(identifier tag,field* fields) 35 | | UNION(identifier tag,field* fields) 36 | | ARRAY(int type,int nelems) 37 | | FUNCTION(int type,int* formals) 38 | | CONST(int type) 39 | | VOLATILE(int type) 40 | attributes(int size,int align) 41 | } 42 | -------------------------------------------------------------------------------- /src/symstub.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mem.h" 5 | #include "symtab.h" 6 | 7 | static char rcsid[] = "$Id$"; 8 | 9 | static struct module *dummy[1]; 10 | static struct module **modules = dummy; 11 | 12 | void _Sym_init(struct module *mods[]) { 13 | if (mods != NULL) 14 | modules = mods; 15 | } 16 | 17 | const char *_Sym_string(const void *str) { return str; } 18 | const struct stype *_Sym_type(const void *type) { return type; } 19 | const struct ssymbol *_Sym_symbol(const void *sym) { return sym; } 20 | 21 | struct _Sym_iterator { 22 | const struct ssymbol *sym; 23 | void *module; 24 | struct module **m; 25 | }; 26 | 27 | struct _Sym_iterator *_Sym_iterator(const void *context) { 28 | struct _Sym_iterator *it; 29 | 30 | NEW(it); 31 | it->sym = _Sym_symbol(context); 32 | it->m = modules; 33 | if (it->sym != NULL) 34 | it->module = it->sym->module; 35 | else 36 | it->module = NULL; 37 | return it; 38 | } 39 | 40 | const struct ssymbol *_Sym_next(struct _Sym_iterator *it) { 41 | assert(it); 42 | for (;;) 43 | if (it->sym != NULL) { 44 | const struct ssymbol *sym = it->sym; 45 | it->sym = _Sym_symbol(sym->uplink); 46 | return sym; 47 | } else { 48 | while (*it->m != NULL && *it->m == it->module) 49 | it->m++; 50 | if (*it->m != NULL) { 51 | it->sym = _Sym_symbol((*it->m)->globals); 52 | it->m++; 53 | } else 54 | return NULL; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/symtab.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mem.h" 4 | #include "seq.h" 5 | #include "symtab.h" 6 | 7 | static char rcsid[] = "$Id$"; 8 | 9 | Seq_T pickles, modules; 10 | 11 | static void inhale(const char *file) { 12 | FILE *f = fopen(file, "rb"); 13 | 14 | if (f != NULL) { 15 | int c; 16 | sym_module_ty pickle; 17 | fprintf(stderr, "inhaling"); 18 | pickle = sym_read_module(f); 19 | fprintf(stderr, " %s[%d]\n", pickle->file, pickle->uname); 20 | Seq_addhi(pickles, pickle); 21 | fclose(f); 22 | } else 23 | fprintf(stderr, "!can't inhale %s\n", file); 24 | } 25 | 26 | void _Sym_init(struct module *mods[]) { 27 | int i; 28 | 29 | pickles = Seq_new(0); 30 | modules = Seq_new(0); 31 | for (i = 0; ; i++) { 32 | char name[25]; 33 | struct module *m, *mod; 34 | int n = _Nub_fetch(0, &mods[i], &m, sizeof m); 35 | assert(n == sizeof m); 36 | if (m == NULL) 37 | break; 38 | NEW(mod); 39 | fprintf(stderr, "fetching module"); 40 | n = _Nub_fetch(0, m, mod, sizeof *mod); 41 | assert(n == sizeof *mod); 42 | fprintf(stderr, " [%d] ", mod->uname); 43 | Seq_addhi(modules, mod); 44 | sprintf(name, "%d.pickle", mod->uname); 45 | inhale(name); 46 | } 47 | } 48 | 49 | void *_Sym_address(sym_symbol_ty sym) { 50 | int i, index, count = Seq_length(modules); 51 | 52 | assert(sym); 53 | if (sym->kind == sym_STATIC_enum) 54 | index = sym->v.sym_STATIC.index; 55 | else if (sym->kind == sym_GLOBAL_enum) 56 | index = sym->v.sym_GLOBAL.index; 57 | else 58 | assert(0); 59 | for (i = 0; i < count; i++) { 60 | struct module *m = Seq_get(modules, i); 61 | if (m->uname == sym->module) { 62 | void *addr; 63 | int n = _Nub_fetch(0, m->addresses + index, &addr, sizeof addr); 64 | assert(n == sizeof addr); 65 | return addr; 66 | } 67 | } 68 | return NULL; 69 | } 70 | 71 | const sym_module_ty _Sym_module(int uname) { 72 | int i, count = Seq_length(pickles); 73 | 74 | for (i = 0; i < count; i++) { 75 | sym_module_ty m = Seq_get(pickles, i); 76 | if (m->uname == uname) 77 | return m; 78 | } 79 | return NULL; 80 | } 81 | 82 | static void *resolve(int uname, int uid) { 83 | sym_module_ty m = _Sym_module(uname); 84 | 85 | if (m != NULL) { 86 | int i, count = Seq_length(m->items); 87 | for (i = 0; i < count; i++) { 88 | sym_item_ty item = Seq_get(m->items, i); 89 | if (item->uid == uid) 90 | switch (item->kind) { 91 | case sym_Symbol_enum: return item->v.sym_Symbol.symbol; 92 | case sym_Type_enum: return item->v.sym_Type.type; 93 | default: assert(0); 94 | } 95 | } 96 | } 97 | return NULL; 98 | } 99 | 100 | const sym_symbol_ty _Sym_symbol(int uname, int uid) { 101 | return resolve(uname, uid); 102 | } 103 | 104 | const sym_type_ty _Sym_type(int uname, int uid) { 105 | return resolve(uname, uid); 106 | } 107 | 108 | const sym_symbol_ty _Sym_lookup(const char *file, const char *name, sym_symbol_ty sym) { 109 | int i, count; 110 | 111 | for ( ; sym != NULL && sym->uplink > 0; sym = _Sym_symbol(sym->module, sym->uplink)) 112 | if (strcmp(name, sym->id) == 0 && (file == NULL || strcmp(file, sym->src->file) == 0)) 113 | return sym; 114 | count = Seq_length(pickles); 115 | for (i = 0; i < count; i++) { 116 | sym_module_ty pickle = Seq_get(pickles, i); 117 | sym = _Sym_symbol(pickle->uname, pickle->globals); 118 | for ( ; sym != NULL && sym->uplink > 0; sym = _Sym_symbol(sym->module, sym->uplink)) 119 | if (strcmp(name, sym->id) == 0 && (file == NULL || strcmp(file, sym->src->file) == 0)) 120 | return sym; 121 | } 122 | return NULL; 123 | } 124 | 125 | Seq_T _Sym_visible(sym_symbol_ty sym) { 126 | int i, count = Seq_length(pickles), uname = 0; 127 | Seq_T syms = Seq_new(0); 128 | 129 | if (sym != NULL) 130 | uname = sym->module; 131 | for ( ; sym != NULL && sym->uplink > 0; sym = _Sym_symbol(sym->module, sym->uplink)) 132 | Seq_addhi(syms, sym); 133 | for (i = 0; i < count; i++) { 134 | sym_module_ty pickle = Seq_get(pickles, i); 135 | if (pickle->uname == uname) 136 | continue; 137 | sym = _Sym_symbol(pickle->uname, pickle->globals); 138 | for ( ; sym != NULL && sym->uplink > 0; sym = _Sym_symbol(sym->module, sym->uplink)) 139 | Seq_addhi(syms, sym); 140 | } 141 | return syms; 142 | } 143 | -------------------------------------------------------------------------------- /src/symtab.h: -------------------------------------------------------------------------------- 1 | #ifndef SYMTAB_INCLUDED 2 | #define SYMTAB_INCLUDED 3 | #include "glue.h" 4 | #include "seq.h" 5 | #include "sym.h" 6 | 7 | /* $Id$ */ 8 | 9 | extern Seq_T modules, pickles; 10 | 11 | extern void _Sym_init(struct module *mods[]); 12 | extern void *_Sym_address(sym_symbol_ty sym); 13 | extern const sym_symbol_ty _Sym_lookup(const char *file, const char *name, sym_symbol_ty sym); 14 | extern const sym_module_ty _Sym_module(int uname); 15 | extern const sym_symbol_ty _Sym_symbol(int uname, int uid); 16 | extern const sym_type_ty _Sym_type(int uname, int uid); 17 | extern Seq_T _Sym_visible(sym_symbol_ty sym); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /startup/irix.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/startup/irix.o -------------------------------------------------------------------------------- /startup/linux.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/startup/linux.o -------------------------------------------------------------------------------- /startup/osf.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/startup/osf.o -------------------------------------------------------------------------------- /startup/solaris.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/startup/solaris.o -------------------------------------------------------------------------------- /startup/ultrix.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/startup/ultrix.o -------------------------------------------------------------------------------- /startup/win32.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drh/cdb/26aae23f8c2fd2d27e83fc88d3943950f3e0cadc/startup/win32.obj -------------------------------------------------------------------------------- /wf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lookup.h" 3 | 4 | static int isletter(int c) { 5 | if (c >= 'A' && c <= 'Z') 6 | c += 'a' - 'A'; 7 | if (c >= 'a' && c <= 'z') 8 | return c; 9 | return 0; 10 | } 11 | 12 | static int getword(char *buf) { 13 | char *s; 14 | int c; 15 | 16 | while ((c = getchar()) != -1 && isletter(c) == 0) 17 | ; 18 | for (s = buf; (c = isletter(c)) != 0; c = getchar()) 19 | *s++ = c; 20 | *s = 0; 21 | if (s > buf) 22 | return 1; 23 | return 0; 24 | } 25 | 26 | void tprint(struct node *tree) { 27 | if (tree) { 28 | tprint(tree->left); 29 | printf("%d\t%s\n", tree->count, tree->word); 30 | tprint(tree->right); 31 | } 32 | } 33 | 34 | static struct node *words = NULL; 35 | 36 | int main(int argc, char *argv[]) { 37 | char buf[40]; 38 | 39 | while (getword(buf)) 40 | lookup(buf, &words)->count++; 41 | tprint(words); 42 | return 0; 43 | } 44 | --------------------------------------------------------------------------------