New utility for interfaces.
[dyninst.git] / igen / src / main.C
1 /*
2  * main.C - main function of the interface compiler igen.
3  *
4  * $Log: main.C,v $
5  * Revision 1.1  1994/01/25 20:48:43  hollings
6  * New utility for interfaces.
7  * new utility for interfaces.
8  *
9  *
10  */
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/file.h>
16
17 #include <util/list.h>
18 #include <util/stringPool.h>
19
20 #include "parse.h"
21
22 int yyparse();
23 int emitCode;
24 int emitHeader;
25 char *codeFile;
26 char *serverFile;
27 char *clientFile;
28 int generateXDR;
29 int generatePVM;
30 stringPool pool;
31 char *headerFile;
32 extern FILE *yyin;
33 int generateTHREAD;
34 char *transportBase;
35 char *serverTypeName;
36 List <typeDefn *> types;
37 interfaceSpec *currentInterface;
38
39 void usage(char *name)
40 {
41     printf("%s -xdr | -thread | -pvm [-header | -code] <fileName>\n", name);
42     exit(-1);
43 }
44
45 void interfaceSpec::generateThreadLoop()
46 {
47     List <remoteFunc*> cf;
48
49     unionName = genVariable();
50     printf("union %s {\n", unionName);
51     for (cf = methods; *cf; cf++) {
52         printf("    struct %s %s;\n", (*cf)->structName, (*cf)->name);
53     }
54     printf("};\n\n");
55
56     printf("int %s::mainLoop(void)\n", name);
57     printf("{\n");
58     printf("  unsigned int __len__;\n");
59     printf("  unsigned int __msgTag__;\n");
60     printf("  union %s __recvBuffer__;\n", unionName);
61     printf("\n");
62     printf("  __msgTag__ = MSG_TAG_ANY;\n");
63     printf("  __len__ = sizeof(__recvBuffer__);\n");
64     printf("  requestingThread = msg_recv(&__msgTag__, &__recvBuffer__, &__len__);\n");
65     printf("  switch (__msgTag__) {\n");
66     for (cf = methods; *cf; cf++) {
67         (*cf)->genSwitch(FALSE);
68     }
69     printf("    default:\n");
70     printf("        return(__msgTag__);\n");
71     printf("  }\n");
72     printf("  return(0);\n");
73     printf("}\n");
74 }
75
76 void interfaceSpec::generateXDRLoop()
77 {
78     List <remoteFunc*> cf;
79
80     printf("int %s::mainLoop(void)\n", name);
81     printf("{\n");
82     printf("    unsigned int __msgTag__, __status__;\n");
83     printf("    __xdrs__->x_op = XDR_DECODE;\n");
84     printf("    xdrrec_skiprecord(__xdrs__);\n");
85     printf("    __status__ = xdr_int(__xdrs__, &__msgTag__);\n");
86     printf("    if (!__status__) return(-1);\n");
87     printf("    switch (__msgTag__) {\n");
88
89     // generate the zero RPC that returns interface name & version.
90     printf("        case 0:\n");
91     printf("            char *__ProtocolName__ = \"%s\";\n", name);
92     printf("            int __val__;\n");
93     printf("            __xdrs__->x_op = XDR_ENCODE;\n");
94     printf("            __val__ = 0;\n");
95     printf("            xdr_int(__xdrs__, &__val__);\n");
96     printf("            xdr_String(__xdrs__, &__ProtocolName__);\n");
97     printf("            __val__ = %d;\n", version);
98     printf("            xdr_int(__xdrs__, &__val__);\n");
99     printf("            xdrrec_endofrecord(__xdrs__, TRUE);\n");
100     printf("            break;\n");
101
102     for (cf = methods; *cf; cf++) {
103         (*cf)->genSwitch(FALSE);
104     }
105     printf("    default:\n");
106     printf("        return(__msgTag__);\n");
107     printf("  }\n");
108     printf("  return(0);\n");
109     printf("}\n");
110 }
111
112
113
114 void interfaceSpec::genIncludes()
115 {
116     printf("#include <stdio.h>\n");
117     printf("#include <stdlib.h>\n");
118     printf("#include <assert.h>\n");
119     if (generateTHREAD) {
120         printf("extern \"C\" {\n");
121         printf("#include \"thread/thread.h\"\n");
122         printf("}\n");
123     }
124     if (generateXDR) {
125         printf("extern \"C\" {\n");
126         printf("#include <rpc/types.h>\n");
127         printf("#include <rpc/xdr.h>\n");
128         printf("}\n");
129     }
130
131     printf("#include \"%s\"\n\n", headerFile);
132 }
133
134 void interfaceSpec::generateServerCode()
135 {
136     List<remoteFunc*> cf;
137
138     if (generateTHREAD) {
139         generateThreadLoop();
140     } else if (generateXDR) {
141         FILE *sf;
142
143         // needs to go into a seperate file.
144         fflush(stdout);
145
146         sf = fopen(serverFile, "w");
147         dup2(sf->_file, 1);
148
149         genIncludes();
150
151         generateXDRLoop();
152     }
153
154     // generate stubs for upcalls.
155     for (cf = methods; *cf; cf++) {
156         (*cf)->genStub(name, TRUE);
157     }
158 }
159
160
161 void interfaceSpec::genWaitLoop() 
162 {
163     List<remoteFunc*> cf;
164
165     // generate a loop to wait for a tag, and call upcalls as the arrive.
166     printf("void %sUser::awaitResponce(int __targetTag__) {\n", name);
167     printf("    unsigned int __tag__;\n");
168     if (generateTHREAD) {
169         printf("  union %s __recvBuffer__;\n", unionName);
170         printf("  unsigned __len__ = sizeof(__recvBuffer__);\n");
171     }
172     printf("  while (1) {\n");
173     if (generateXDR) {
174         printf("    __xdrs__->x_op = XDR_DECODE;\n");
175         printf("    xdrrec_skiprecord(__xdrs__);\n");
176         printf("    xdr_int(__xdrs__, &__tag__);\n");
177     } else if (generateTHREAD) {
178         printf("  __tag__ = MSG_TAG_ANY;\n");
179         printf("    requestingThread = msg_recv(&__tag__, (void *) &__recvBuffer__, &__len__); \n");
180     }
181     printf("    if (__tag__ == __targetTag__) return;\n");
182     printf("    switch (__tag__) {\n");
183     for (cf = methods; *cf; cf++) {
184         (*cf)->genSwitch(TRUE);
185     }
186     printf("        default: \n        abort();\n");
187     printf("    }\n");
188     printf("    if (__targetTag__ == -1) return;\n");
189     printf("  }\n");
190     printf("}\n");
191
192     printf("int %sUser::isValidUpCall(int tag) {\n", name);
193     printf("    return((tag >= %d) && (tag <= %d));\n", baseTag, boundTag);
194     printf("}\n");
195 }
196
197 void interfaceSpec::genProtoVerify()
198 {
199     // generate stub to verify version.
200     printf("void %sUser::verifyProtocolAndVersion() {\n", name);
201     printf("    unsigned int __tag__;\n");
202     printf("    String proto;\n");
203     printf("    int version;\n");
204     printf("    __tag__ = 0;\n");
205     printf("    __xdrs__->x_op = XDR_ENCODE;\n");
206     printf("    xdr_int(__xdrs__, &__tag__);\n");
207     printf("    xdrrec_endofrecord(__xdrs__, TRUE);\n");
208     printf("    awaitResponce(0);\n");
209     printf("    xdr_String(__xdrs__, &(proto));\n");
210     printf("    xdr_int(__xdrs__, &(version));\n");
211     printf("    if ((version != %d) || (strcmp(proto, \"%s\"))) {\n",
212         version, name);
213     printf("        printf(\"protocol %s version %d expected\\n\");\n", 
214         name, version);
215     printf("        printf(\"protocol %%s version %%d found\\n\", proto, version);\n");
216     printf("        exit(-1);\n");
217     printf("    }\n");
218     printf("}\n");
219     printf("\n\n");
220     printf("%sUser::%sUser(int fd, xdrIOFunc r, xdrIOFunc w):\n", name, name);
221     printf("XDRrpc(fd, r, w) { if (__xdrs__) verifyProtocolAndVersion(); }\n");
222     printf("%sUser::%sUser(char *m,char *l,char *p,xdrIOFunc r,xdrIOFunc w):\n",
223         name, name);
224     printf("    XDRrpc(m, l, p, r, w) { if (__xdrs__) \n");
225     printf("       verifyProtocolAndVersion(); }\n");
226     printf("\n");
227 }
228
229
230 void interfaceSpec::generateStubs()
231 {
232     List <remoteFunc*> cf;
233     char className[80];
234
235     sprintf(className, "%sUser", name);
236     for (cf = methods; *cf; cf++) {
237         (*cf)->genStub(className, FALSE);
238     }
239 }
240
241 void interfaceSpec::generateClientCode()
242 {
243     if (generateXDR) {
244         FILE *cf;
245
246         // needs to go into a seperate file.
247         fflush(stdout);
248
249         cf = fopen(clientFile, "w");
250         dup2(cf->_file, 1);
251
252         genIncludes();
253     }
254
255     generateStubs();
256
257     if (generateXDR) {
258         genProtoVerify();
259     }
260
261     genWaitLoop();
262 }
263
264 void interfaceSpec::generateBundlers()
265 {
266     List <typeDefn*> cs;
267
268     for (cs = types; *cs; cs++) {
269         (*cs)->genBundler();
270     }
271 }
272
273 int main(int argc, char *argv[])
274 {
275     int i;
276     FILE *of;
277     char *temp;
278     char *file;
279
280     /* define pre-defined types */
281     (void) new typeDefn("int");
282     (void) new typeDefn("double");
283     (void) new typeDefn("String");
284     (void) new typeDefn("void");
285     (void) new typeDefn("Boolean");
286
287     emitCode = 1;
288     emitHeader = 1;
289     for (i=0; i < argc-1; i++) {
290         if (!strcmp("-pvm", argv[i])) {
291             generatePVM = 1;
292             generateXDR = 0;
293             generateTHREAD = 0;
294             serverTypeName = pool.findAndAdd("int");
295         } if (!strcmp("-xdr", argv[i])) {
296             generatePVM = 0;
297             generateXDR = 1;
298             generateTHREAD = 0;
299             (void) new typeDefn("XDRptr");
300             serverTypeName = pool.findAndAdd("XDRptr");
301             transportBase = "XDRrpc";
302         } if (!strcmp("-thread", argv[i])) {
303             generatePVM = 0;
304             generateXDR = 0;
305             generateTHREAD = 1;
306             serverTypeName = pool.findAndAdd("int");
307             transportBase = "THREADrpc";
308         } else if (!strcmp("-header", argv[i])) {
309             emitCode = 0;
310             emitHeader = 1;
311         } else if (!strcmp("-code", argv[i])) {
312             emitCode = 1;
313             emitHeader = 0;
314         }
315     }
316     if (!emitHeader && !emitCode) {
317         usage(argv[0]);
318     }
319     if (!generatePVM && !generateXDR && !generateTHREAD) {
320         usage(argv[0]);
321     }
322
323     file = argv[argc-1];
324
325     yyin = fopen(file, "r");
326     if (!yyin) {
327         printf("unable to open %s\n", file);
328         exit(-1);
329     }
330
331     // skip to trailing component of file name.
332     temp = strrchr(file, '/');
333     if (temp) file = temp+1;
334
335     temp = strstr(file, ".I");
336     if (!temp) {
337         printf("file names must end in .I\n");
338         exit(-1);
339     }
340     *(temp+1) = '\0';
341
342     headerFile = (char *) malloc(strlen(file)+1);
343     sprintf(headerFile, "%sh", file);
344
345     codeFile = (char *) malloc(strlen(file)+1);
346     sprintf(codeFile, "%sC", file);
347
348     serverFile = (char *) malloc(strlen(file)+6);
349     sprintf(serverFile, "%sSRVR.C", file);
350
351     clientFile = (char *) malloc(strlen(file)+6);
352     sprintf(clientFile, "%sCLNT.C", file);
353
354     if (emitHeader) {
355         of = fopen(headerFile, "w");
356         dup2(of->_file, 1);
357         printf("#include \"util/rpcUtil.h\"\n");
358     }
359
360     yyparse();
361
362     if (emitHeader) {
363         fflush(stdout);
364         fclose(of);
365     }
366
367     if (emitCode) {
368         FILE *cf;
369
370         cf = fopen(codeFile, "w");
371         dup2(cf->_file, 1);
372
373         currentInterface->genIncludes();
374         if (generateXDR || generatePVM) currentInterface->generateBundlers();
375
376         currentInterface->generateServerCode();
377
378         currentInterface->generateClientCode();
379         fflush(stdout);
380     }
381
382     exit(0);
383 }
384
385 char *interfaceSpec::genVariable()
386 {
387     static int count;
388     char *ret;
389
390     ret = (char *) malloc(20);
391     sprintf(ret, "%s__%d", name, count++);
392     return(ret);
393 }
394
395 int interfaceSpec::getNextTag()
396 {
397     return(++boundTag);
398 }
399
400 void remoteFunc::genMethodHeader(char *className)
401 {
402     int spitOne;
403     List <char *> cl;
404     List<argument*> lp;
405
406     if (className) {
407         printf("%s %s::%s(", retType, className, name);
408     } else {
409         printf("%s %s(", retType, name);
410     }
411     for (lp = args, spitOne = 0; *lp; lp++) {
412         if (spitOne) printf(",");
413         spitOne =1;
414         printf("%s ", (*lp)->type);
415         for (cl = *(*lp)->stars; *cl; cl++) printf("*");
416         printf("%s", (*lp)->name);
417     }
418     if (!spitOne) printf("void");
419     printf(")");
420 }
421
422 void remoteFunc::genSwitch(Boolean forUpcalls)
423 {
424     int first;
425     List <argument *> ca;
426
427
428     if (forUpcalls && (upcall == notUpcall)) return;
429     if (!forUpcalls && (upcall != notUpcall)) return;
430
431     printf("        case %s_%s_REQ: {\n", spec->getName(), name);
432     printf("            ");
433     printf("        int __val__;\n");
434     if (strcmp(retType, "void")) {
435         printf("            %s __ret__;\n", retType);
436     }
437     if (generateXDR) {
438         printf("            extern xdr_%s(XDR*, %s*);\n", retType, retType);
439         printf("            %s __recvBuffer__;\n", structName);
440         for (ca = args; *ca; ca++) {
441             printf("            xdr_%s(__xdrs__, &__recvBuffer__.%s);\n", 
442                 (*ca)->type, (*ca)->name);
443         }
444     }
445     if (strcmp(retType, "void")) {
446         printf("            __ret__ = %s(", name);
447     } else {
448         printf("            %s(", name);
449     }
450     for (ca = args, first = 1; *ca; ca++) {
451         if (!first) printf(",");
452         first = 0;
453         if (generateTHREAD) {
454             printf("__recvBuffer__.%s.%s", name, (*ca)->name);
455         } else if (generateXDR) {
456             printf("__recvBuffer__.%s", (*ca)->name);
457         }
458     }
459     printf(");\n");
460     if (generateTHREAD && (upcall != asyncUpcall)) {
461         if (strcmp(retType, "void")) {
462             printf("        __val__ = msg_send(requestingThread, %s_%s_RESP, (void *) &__ret__, sizeof(%s));\n", spec->getName(), name, retType);
463         } else {
464             printf("        __val__ = msg_send(requestingThread, %s_%s_RESP, NULL, 0);\n", 
465                 spec->getName(), name);
466         }
467         printf("            assert(__val__ == THR_OKAY);\n");
468     } else if (generateXDR && (upcall != asyncUpcall)) {
469         printf("            __xdrs__->x_op = XDR_ENCODE;\n");
470         printf("            __val__ = %s_%s_RESP;\n", spec->getName(), name);
471         printf("            xdr_int(__xdrs__, &__val__);\n");
472         if (strcmp(retType, "void")) {
473             printf("            xdr_%s(__xdrs__,&__ret__);\n", retType);
474         }
475         printf("            xdrrec_endofrecord(__xdrs__, TRUE);\n");
476     }
477     printf("            break;\n         }\n\n");
478 }
479
480
481 void remoteFunc::genThreadStub(char *className)
482 {
483     List<argument*> lp;
484     char *retVar = spec->genVariable();
485     char *structUseName = spec->genVariable();
486
487     genMethodHeader(className);
488     printf(" {\n");
489
490     printf("    struct %s %s;\n", structName, structUseName);
491     printf("    unsigned int __tag__;\n");
492     printf("    unsigned int __len__;\n");
493     printf("    int __val__;\n");
494     if (strcmp(retType, "void")) {
495         printf("    %s %s;\n", retType, retVar);
496     }
497     for (lp = args; *lp; lp++) {
498         printf("    %s.%s = %s;  \n",structUseName,
499             (*lp)->name, (*lp)->name);
500     }
501     if (*args) {
502         printf("    __val__ = msg_send(tid, %s_%s_REQ, (void *) &%s, sizeof(%s));\n",
503             spec->getName(), name, structUseName, structUseName);
504     } else {
505         printf("    __val__ = msg_send(tid, %s_%s_REQ, NULL, 0); \n", 
506             spec->getName(), name);
507     }
508     printf("    assert(__val__ == THR_OKAY);\n");
509     if (upcall != asyncUpcall) {
510         printf("    __tag__ = %s_%s_RESP;\n", spec->getName(), name);
511         if (strcmp(retType, "void")) {
512             printf("    __len__ = sizeof(%s);\n", retVar);
513             printf("    msg_recv(&__tag__, (void *) &%s, &__len__); \n",retVar);
514             printf("    assert(__len__ == sizeof(%s));\n", retVar);
515             printf("    return(%s);\n", retVar);
516         } else {
517             printf("    msg_recv(&__tag__, NULL, 0); \n",spec->getName(), name);
518         }
519         printf("    assert(__tag__ == %s_%s_RESP);\n",spec->getName(),name);
520     }
521     printf("}\n\n");
522 }
523
524 void remoteFunc::genXDRStub(char *className)
525 {
526     List<argument*> lp;
527     char *retVar = spec->genVariable();
528
529     genMethodHeader(className);
530     printf(" {\n");
531
532     printf("    unsigned int __tag__;\n");
533     printf("    int __val__;\n");
534     if (strcmp(retType, "void")) {
535         printf("    unsigned int __len__;\n");
536         printf("    %s %s;\n", retType, retVar);
537     }
538     printf("    __tag__ = %s_%s_REQ;\n", spec->getName(), name);
539     printf("    __xdrs__->x_op = XDR_ENCODE;\n");
540     printf("    xdr_int(__xdrs__, &__tag__);\n");
541     for (lp = args; *lp; lp++) {
542         printf("    xdr_%s(__xdrs__, &%s);\n", (*lp)->type, (*lp)->name);
543     }
544     printf("    xdrrec_endofrecord(__xdrs__, TRUE);\n");
545     if (upcall != asyncUpcall) {
546         if (upcall == notUpcall) {
547             printf("    awaitResponce(%s_%s_RESP);\n",spec->getName(), name);
548         } else if (upcall == syncUpcall) {
549             printf("    __xdrs__->x_op = XDR_DECODE;\n");
550             printf("    xdrrec_skiprecord(__xdrs__);\n");
551             printf("    xdr_int(__xdrs__, &__tag__);\n");
552             printf("    assert(__tag__ == %s_%s_RESP);\n", spec->getName(), name);
553         }
554         if (strcmp(retType, "void")) {
555             printf("    xdr_%s(__xdrs__, &(%s)); \n", retType, retVar);
556             printf("    return(%s);\n", retVar);
557         }
558     }
559     printf("}\n\n");
560 }
561
562 void remoteFunc::genStub(char *className, Boolean forUpcalls)
563 {
564     if (forUpcalls && (upcall == notUpcall)) return;
565     if (!forUpcalls && (upcall != notUpcall)) return;
566
567     printf("\n");
568     if (generateXDR) {
569         genXDRStub(className);
570     } else if (generateTHREAD) {
571         genThreadStub(className);
572     }
573 }
574
575 void remoteFunc::genHeader()
576 {
577     List<char *> cl;
578     List<argument*> lp;
579
580     printf("struct %s {\n", structName);
581     for (lp = args; *lp; lp++) {
582         printf("    %s ", (*lp)->type);
583         for (cl = *(*lp)->stars; *cl; cl++) printf("*");
584         printf("%s", (*lp)->name);
585         printf(";\n");
586     }
587     printf("};\n\n");
588
589     printf("#define %s_%s_REQ %d\n", spec->getName(),name, spec->getNextTag());
590     printf("#define %s_%s_RESP %d\n", spec->getName(), name,spec->getNextTag());
591 }
592
593 void typeDefn::genHeader()
594 {
595     List<field*> fp;
596
597     printf("#ifndef %s_TYPE\n", name);
598     printf("#define %s_TYPE\n", name);
599     printf("class %s {  \npublic:\n", name);
600     if (arrayType) {
601         printf("    int count;\n");
602         printf("    %s* data;\n", type);
603     } else {
604         for (fp = fields; *fp; fp++) {
605             (*fp)->genHeader();
606         }
607     }
608     printf("};\n\n");
609     printf("#endif\n");
610
611     if (generateXDR) {
612         if (userDefined) printf("extern xdr_%s(XDR*, %s*);\n", name, name);
613     }
614 }
615
616
617 void typeDefn::genBundler()
618 {
619     List<field*> fp;
620
621     if (!userDefined) return;
622
623     printf("bool_t xdr_%s(XDR *__xdrs__, %s *__ptr__) {\n", name, name);
624     if (arrayType) {
625         printf("if (__xdrs__->x_op == XDR_DECODE) __ptr__->data = NULL;\n");
626         printf("    xdr_array(__xdrs__, &(__ptr__->data), &__ptr__->count, ~0, sizeof(%s), xdr_%s);\n",
627             type, type);
628     } else {
629         for (fp = fields; *fp; fp++) {
630             (*fp)->genBundler();
631         }
632     }
633     printf("    return(TRUE);\n");
634     printf("}\n\n");
635 }
636
637
638 char *findAndAddArrayType(char *name) 
639 {
640     typeDefn *s;
641     char temp[80];
642     char *arrayTypeName;
643
644     // now find the associated array type.
645     sprintf(temp, "%s_Array", name);
646     arrayTypeName = pool.findAndAdd(temp);
647     if (!types.find(arrayTypeName)) {
648         s = new typeDefn(arrayTypeName, name);
649         s->genHeader();
650     }
651     return arrayTypeName;
652 }
653
654 void interfaceSpec::genClass()
655 {
656     List <remoteFunc *> curr; 
657
658     printf("class %sUser: public RPCUser, public %s {\n", name, transportBase);
659     printf("  public:\n");
660     if (generateXDR) {
661         printf("    virtual void verifyProtocolAndVersion();\n");
662         printf("    %sUser(int fd, xdrIOFunc r, xdrIOFunc w);\n", name);
663         printf("    %sUser(char *,char *,char*, xdrIOFunc r, xdrIOFunc w);\n", 
664                 name);
665     }
666     printf("    void awaitResponce(int);\n");
667     printf("    int isValidUpCall(int);\n");
668
669     for (curr = methods; *curr; curr++) {
670         printf("    ");
671         (*curr)->genMethodHeader(NULL);
672         printf(";\n");
673     }
674     printf("};\n");
675
676
677     printf("class %s: private RPCServer, public %s {\n", name, transportBase);
678     printf("  public:\n");
679     printf("    mainLoop(void);\n");
680     for (curr = methods; *curr; curr++) {
681         printf("    ");
682         (*curr)->genMethodHeader(NULL);
683         printf(";\n");
684     }
685     printf("};\n\n");
686 }