URI:
       tbuiltin.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tbuiltin.c (29415B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ctype.h>
            5 #include <mach.h>
            6 #include <regexp.h>
            7 #define Extern extern
            8 #include "acid.h"
            9 #include "y.tab.h"
           10 
           11 void        cvtatof(Node*, Node*);
           12 void        cvtatoi(Node*, Node*);
           13 void        cvtitoa(Node*, Node*);
           14 void        bprint(Node*, Node*);
           15 void        funcbound(Node*, Node*);
           16 void        printto(Node*, Node*);
           17 void        getfile(Node*, Node*);
           18 void        fmt(Node*, Node*);
           19 void        pcfile(Node*, Node*);
           20 void        pcline(Node*, Node*);
           21 void        setproc(Node*, Node*);
           22 void        strace(Node*, Node*);
           23 void        follow(Node*, Node*);
           24 void        reason(Node*, Node*);
           25 void        newproc(Node*, Node*);
           26 void        startstop(Node*, Node*);
           27 void        match(Node*, Node*);
           28 void        status(Node*, Node*);
           29 void        xkill(Node*,Node*);
           30 void        waitstop(Node*, Node*);
           31 void waitsyscall(Node*, Node*);
           32 void        stop(Node*, Node*);
           33 void        start(Node*, Node*);
           34 void        filepc(Node*, Node*);
           35 void        doerror(Node*, Node*);
           36 void        rc(Node*, Node*);
           37 void        doaccess(Node*, Node*);
           38 void        map(Node*, Node*);
           39 void        readfile(Node*, Node*);
           40 void        interpret(Node*, Node*);
           41 void        include(Node*, Node*);
           42 void        includepipe(Node*, Node*);
           43 void        regexp(Node*, Node*);
           44 void textfile(Node*, Node*);
           45 void deltextfile(Node*, Node*);
           46 void stringn(Node*, Node*);
           47 void xregister(Node*, Node*);
           48 void refconst(Node*, Node*);
           49 void dolook(Node*, Node*);
           50 void step1(Node*, Node*);
           51 
           52 typedef struct Btab Btab;
           53 struct Btab
           54 {
           55         char        *name;
           56         void        (*fn)(Node*, Node*);
           57 } tab[] =
           58 {
           59         "access",        doaccess,
           60         "atof",                cvtatof,
           61         "atoi",                cvtatoi,
           62         "deltextfile",        deltextfile,
           63         "error",        doerror,
           64         "file",                getfile,
           65         "filepc",        filepc,
           66         "fnbound",        funcbound,
           67         "fmt",                fmt,
           68         "follow",        follow,
           69         "include",        include,
           70         "includepipe",        includepipe,
           71         "interpret",        interpret,
           72         "itoa",                cvtitoa,
           73         "kill",                xkill,
           74         "map",                map,
           75         "match",        match,
           76         "newproc",        newproc,
           77         "pcfile",        pcfile,
           78         "pcline",        pcline,
           79         "print",        bprint,
           80         "printto",        printto,
           81         "rc",                rc,
           82         "readfile",        readfile,
           83         "reason",        reason,
           84         "refconst",        refconst,
           85         "regexp",        regexp,
           86         "register",        xregister,
           87         "setproc",        setproc,
           88         "start",        start,
           89         "startstop",        startstop,
           90         "status",        status,
           91         "step1",        step1,
           92         "stop",                stop,
           93         "strace",        strace,
           94         "stringn",        stringn,
           95         "textfile",        textfile,
           96         "var",        dolook,
           97         "waitstop",        waitstop,
           98         "waitsyscall",        waitsyscall,
           99         0
          100 };
          101 
          102 void
          103 mkprint(Lsym *s)
          104 {
          105         prnt = malloc(sizeof(Node));
          106         memset(prnt, 0, sizeof(Node));
          107         prnt->op = OCALL;
          108         prnt->left = malloc(sizeof(Node));
          109         memset(prnt->left, 0, sizeof(Node));
          110         prnt->left->sym = s;
          111 }
          112 
          113 void
          114 installbuiltin(void)
          115 {
          116         Btab *b;
          117         Lsym *s;
          118 
          119         b = tab;
          120         while(b->name) {
          121                 s = look(b->name);
          122                 if(s == 0)
          123                         s = enter(b->name, Tid);
          124 
          125                 s->builtin = b->fn;
          126                 if(b->fn == bprint)
          127                         mkprint(s);
          128                 b++;
          129         }
          130 }
          131 
          132 void
          133 match(Node *r, Node *args)
          134 {
          135         int i;
          136         List *f;
          137         Node *av[Maxarg];
          138         Node resi, resl;
          139 
          140         na = 0;
          141         flatten(av, args);
          142         if(na != 2)
          143                 error("match(obj, list): arg count");
          144 
          145         expr(av[1], &resl);
          146         if(resl.type != TLIST)
          147                 error("match(obj, list): need list");
          148         expr(av[0], &resi);
          149 
          150         r->op = OCONST;
          151         r->type = TINT;
          152         r->store.fmt = 'D';
          153         r->store.u.ival = -1;
          154 
          155         i = 0;
          156         for(f = resl.store.u.l; f; f = f->next) {
          157                 if(resi.type == f->type) {
          158                         switch(resi.type) {
          159                         case TINT:
          160                                 if(resi.store.u.ival == f->store.u.ival) {
          161                                         r->store.u.ival = i;
          162                                         return;
          163                                 }
          164                                 break;
          165                         case TFLOAT:
          166                                 if(resi.store.u.fval == f->store.u.fval) {
          167                                         r->store.u.ival = i;
          168                                         return;
          169                                 }
          170                                 break;
          171                         case TSTRING:
          172                                 if(scmp(resi.store.u.string, f->store.u.string)) {
          173                                         r->store.u.ival = i;
          174                                         return;
          175                                 }
          176                                 break;
          177                         case TLIST:
          178                                 error("match(obj, list): not defined for list");
          179                         }
          180                 }
          181                 i++;
          182         }
          183 }
          184 
          185 void
          186 newproc(Node *r, Node *args)
          187 {
          188         int i;
          189         Node res;
          190         char *p, *e;
          191         char *argv[Maxarg], buf[Strsize];
          192 
          193         i = 1;
          194         argv[0] = symfil;
          195 
          196         if(args) {
          197                 expr(args, &res);
          198                 if(res.type != TSTRING)
          199                         error("newproc(): arg not string");
          200                 if(res.store.u.string->len >= sizeof(buf))
          201                         error("newproc(): too many arguments");
          202                 memmove(buf, res.store.u.string->string, res.store.u.string->len);
          203                 buf[res.store.u.string->len] = '\0';
          204                 p = buf;
          205                 e = buf+res.store.u.string->len;
          206                 for(;;) {
          207                         while(p < e && (*p == '\t' || *p == ' '))
          208                                 *p++ = '\0';
          209                         if(p >= e)
          210                                 break;
          211                         argv[i++] = p;
          212                         if(i >= Maxarg)
          213                                 error("newproc: too many arguments");
          214                         while(p < e && *p != '\t' && *p != ' ')
          215                                 p++;
          216                 }
          217         }
          218         argv[i] = 0;
          219         r->op = OCONST;
          220         r->type = TINT;
          221         r->store.fmt = 'D';
          222         r->store.u.ival = nproc(argv);
          223 }
          224 
          225 void
          226 step1(Node *r, Node *args)
          227 {
          228         Node res;
          229 
          230         USED(r);
          231         if(args == 0)
          232                 error("step1(pid): no pid");
          233         expr(args, &res);
          234         if(res.type != TINT)
          235                 error("step1(pid): arg type");
          236 
          237         msg(res.store.u.ival, "step");
          238         notes(res.store.u.ival);
          239         dostop(res.store.u.ival);
          240 }
          241 
          242 void
          243 startstop(Node *r, Node *args)
          244 {
          245         Node res;
          246 
          247         USED(r);
          248         if(args == 0)
          249                 error("startstop(pid): no pid");
          250         expr(args, &res);
          251         if(res.type != TINT)
          252                 error("startstop(pid): arg type");
          253 
          254         msg(res.store.u.ival, "startstop");
          255         notes(res.store.u.ival);
          256         dostop(res.store.u.ival);
          257 }
          258 
          259 void
          260 waitstop(Node *r, Node *args)
          261 {
          262         Node res;
          263 
          264         USED(r);
          265         if(args == 0)
          266                 error("waitstop(pid): no pid");
          267         expr(args, &res);
          268         if(res.type != TINT)
          269                 error("waitstop(pid): arg type");
          270 
          271         Bflush(bout);
          272         msg(res.store.u.ival, "waitstop");
          273         notes(res.store.u.ival);
          274         dostop(res.store.u.ival);
          275 }
          276 
          277 void
          278 waitsyscall(Node *r, Node *args)
          279 {
          280         Node res;
          281 
          282         USED(r);
          283         if(args == 0)
          284                 error("waitsyscall(pid): no pid");
          285         expr(args, &res);
          286         if(res.type != TINT)
          287                 error("waitsycall(pid): arg type");
          288 
          289         Bflush(bout);
          290         msg(res.store.u.ival, "sysstop");
          291         notes(res.store.u.ival);
          292         dostop(res.store.u.ival);
          293 }
          294 
          295 void
          296 start(Node *r, Node *args)
          297 {
          298         Node res;
          299 
          300         USED(r);
          301         if(args == 0)
          302                 error("start(pid): no pid");
          303         expr(args, &res);
          304         if(res.type != TINT)
          305                 error("start(pid): arg type");
          306 
          307         msg(res.store.u.ival, "start");
          308 }
          309 
          310 void
          311 stop(Node *r, Node *args)
          312 {
          313         Node res;
          314 
          315         USED(r);
          316         if(args == 0)
          317                 error("stop(pid): no pid");
          318         expr(args, &res);
          319         if(res.type != TINT)
          320                 error("stop(pid): arg type");
          321 
          322         Bflush(bout);
          323         msg(res.store.u.ival, "stop");
          324         notes(res.store.u.ival);
          325         dostop(res.store.u.ival);
          326 }
          327 
          328 void
          329 xkill(Node *r, Node *args)
          330 {
          331         Node res;
          332 
          333         USED(r);
          334         if(args == 0)
          335                 error("kill(pid): no pid");
          336         expr(args, &res);
          337         if(res.type != TINT)
          338                 error("kill(pid): arg type");
          339 
          340         msg(res.store.u.ival, "kill");
          341         deinstall(res.store.u.ival);
          342 }
          343 
          344 void
          345 xregister(Node *r, Node *args)
          346 {
          347         int tid;
          348         Regdesc *rp;
          349         Node res, resid;
          350         Node *av[Maxarg];
          351 
          352         na = 0;
          353         flatten(av, args);
          354         if(na != 1/* && na != 2 */)
          355                 error("register(name): arg count");
          356 
          357         expr(av[0], &res);
          358         if(res.type != TSTRING)
          359                 error("register(name): arg type: name should be string");
          360         tid = 0;
          361         if(na == 2){
          362                 expr(av[1], &resid);
          363                 if(resid.type != TINT)
          364                         error("register(name[, threadid]): arg type: threadid should be int");
          365                 tid = resid.store.u.ival;
          366         }
          367         if((rp = regdesc(res.store.u.string->string)) == nil)
          368                 error("no such register");
          369         r->op = OCONST;
          370         r->type = TREG;
          371         r->store.fmt = rp->format;
          372         r->store.u.reg.name = rp->name;
          373         r->store.u.reg.thread = tid;
          374 }
          375 
          376 void
          377 refconst(Node *r, Node *args)
          378 {
          379         Node *n;
          380 
          381         if(args == 0)
          382                 error("refconst(expr): arg count");
          383 
          384         n = an(OCONST, ZN, ZN);
          385         expr(args, n);
          386 
          387         r->op = OCONST;
          388         r->type = TCON;
          389         r->store.u.con = n;
          390 }
          391 
          392 void
          393 dolook(Node *r, Node *args)
          394 {
          395         Node res;
          396         Lsym *l;
          397 
          398         if(args == 0)
          399                 error("var(string): arg count");
          400         expr(args, &res);
          401         if(res.type != TSTRING)
          402                 error("var(string): arg type");
          403 
          404         r->op = OCONST;
          405         if((l = look(res.store.u.string->string)) == nil || l->v->set == 0){
          406                 r->type = TLIST;
          407                 r->store.u.l = nil;
          408         }else{
          409                 r->type = l->v->type;
          410                 r->store = l->v->store;
          411         }
          412 }
          413 
          414 void
          415 status(Node *r, Node *args)
          416 {
          417         Node res;
          418         char *p;
          419 
          420         USED(r);
          421         if(args == 0)
          422                 error("status(pid): no pid");
          423         expr(args, &res);
          424         if(res.type != TINT)
          425                 error("status(pid): arg type");
          426 
          427         p = getstatus(res.store.u.ival);
          428         r->store.u.string = strnode(p);
          429         r->op = OCONST;
          430         r->store.fmt = 's';
          431         r->type = TSTRING;
          432 }
          433 
          434 void
          435 reason(Node *r, Node *args)
          436 {
          437         Node res;
          438 
          439         if(args == 0)
          440                 error("reason(cause): no cause");
          441         expr(args, &res);
          442         if(res.type != TINT)
          443                 error("reason(cause): arg type");
          444 
          445         r->op = OCONST;
          446         r->type = TSTRING;
          447         r->store.fmt = 's';
          448         r->store.u.string = strnode((*mach->exc)(cormap, acidregs));
          449 }
          450 
          451 void
          452 follow(Node *r, Node *args)
          453 {
          454         int n, i;
          455         Node res;
          456         u64int f[10];
          457         List **tail, *l;
          458 
          459         if(args == 0)
          460                 error("follow(addr): no addr");
          461         expr(args, &res);
          462         if(res.type != TINT)
          463                 error("follow(addr): arg type");
          464 
          465         n = (*mach->foll)(cormap, acidregs, res.store.u.ival, f);
          466         if (n < 0)
          467                 error("follow(addr): %r");
          468         tail = &r->store.u.l;
          469         for(i = 0; i < n; i++) {
          470                 l = al(TINT);
          471                 l->store.u.ival = f[i];
          472                 l->store.fmt = 'X';
          473                 *tail = l;
          474                 tail = &l->next;
          475         }
          476 }
          477 
          478 void
          479 funcbound(Node *r, Node *args)
          480 {
          481         int n;
          482         Node res;
          483         u64int bounds[2];
          484         List *l;
          485 
          486         if(args == 0)
          487                 error("fnbound(addr): no addr");
          488         expr(args, &res);
          489         if(res.type != TINT)
          490                 error("fnbound(addr): arg type");
          491 
          492         n = fnbound(res.store.u.ival, bounds);
          493         if (n >= 0) {
          494                 r->store.u.l = al(TINT);
          495                 l = r->store.u.l;
          496                 l->store.u.ival = bounds[0];
          497                 l->store.fmt = 'X';
          498                 l->next = al(TINT);
          499                 l = l->next;
          500                 l->store.u.ival = bounds[1];
          501                 l->store.fmt = 'X';
          502         }
          503 }
          504 
          505 void
          506 setproc(Node *r, Node *args)
          507 {
          508         Node res;
          509 
          510         USED(r);
          511         if(args == 0)
          512                 error("setproc(pid): no pid");
          513         expr(args, &res);
          514         if(res.type != TINT)
          515                 error("setproc(pid): arg type");
          516 
          517         sproc(res.store.u.ival);
          518 }
          519 
          520 void
          521 filepc(Node *r, Node *args)
          522 {
          523         int i;
          524         Node res;
          525         char *p, c;
          526         u64int v;
          527 
          528         if(args == 0)
          529                 error("filepc(filename:line): arg count");
          530         expr(args, &res);
          531         if(res.type != TSTRING)
          532                 error("filepc(filename:line): arg type");
          533 
          534         p = strchr(res.store.u.string->string, ':');
          535         if(p == 0)
          536                 error("filepc(filename:line): bad arg format");
          537 
          538         c = *p;
          539         *p++ = '\0';
          540         i = file2pc(res.store.u.string->string, atoi(p), &v);
          541         p[-1] = c;
          542         if(i < 0)
          543                 error("filepc(filename:line): can't find address");
          544 
          545         r->op = OCONST;
          546         r->type = TINT;
          547         r->store.fmt = 'D';
          548         r->store.u.ival = v;
          549 }
          550 
          551 void
          552 interpret(Node *r, Node *args)
          553 {
          554         Node res;
          555         int isave;
          556 
          557         if(args == 0)
          558                 error("interpret(string): arg count");
          559         expr(args, &res);
          560         if(res.type != TSTRING)
          561                 error("interpret(string): arg type");
          562 
          563         pushstr(&res);
          564 
          565         isave = interactive;
          566         interactive = 0;
          567         r->store.u.ival = yyparse();
          568         interactive = isave;
          569         popio();
          570         r->op = OCONST;
          571         r->type = TINT;
          572         r->store.fmt = 'D';
          573 }
          574 
          575 void
          576 include(Node *r, Node *args)
          577 {
          578         char *file, *libfile;
          579         static char buf[1024];
          580         Node res;
          581         int isave;
          582 
          583         if(args == 0)
          584                 error("include(string): arg count");
          585         expr(args, &res);
          586         if(res.type != TSTRING)
          587                 error("include(string): arg type");
          588 
          589         Bflush(bout);
          590 
          591         libfile = nil;
          592         file = res.store.u.string->string;
          593         if(access(file, AREAD) < 0 && file[0] != '/'){
          594                 snprint(buf, sizeof buf, "#9/acid/%s", file);
          595                 libfile = unsharp(buf);
          596                 if(access(libfile, AREAD) >= 0){
          597                         strecpy(buf, buf+sizeof buf, libfile);
          598                         file = buf;
          599                 }
          600                 free(libfile);
          601         }
          602 
          603         pushfile(file);
          604         isave = interactive;
          605         interactive = 0;
          606         r->store.u.ival = yyparse();
          607         interactive = isave;
          608         popio();
          609         r->op = OCONST;
          610         r->type = TINT;
          611         r->store.fmt = 'D';
          612 }
          613 
          614 void
          615 includepipe(Node *r, Node *args)
          616 {
          617         Node res;
          618         int i, isave, pid, pip[2];
          619         char *argv[4];
          620         Waitmsg *w;
          621 
          622         USED(r);
          623         if(args == 0)
          624                 error("includepipe(string): arg count");
          625         expr(args, &res);
          626         if(res.type != TSTRING)
          627                 error("includepipe(string): arg type");
          628 
          629         Bflush(bout);
          630 
          631         argv[0] = "rc";
          632         argv[1] = "-c";
          633         argv[2] = res.store.u.string->string;
          634         argv[3] = 0;
          635 
          636         if(pipe(pip) < 0)
          637                 error("pipe: %r");
          638 
          639         pid = fork();
          640         switch(pid) {
          641         case -1:
          642                 close(pip[0]);
          643                 close(pip[1]);
          644                 error("fork: %r");
          645         case 0:
          646                 close(pip[0]);
          647                 close(0);
          648                 open("/dev/null", OREAD);
          649                 dup(pip[1], 1);
          650                 if(pip[1] > 1)
          651                         close(pip[1]);
          652                 for(i=3; i<100; i++)
          653                         close(i);
          654                 exec("rc", argv);
          655                 sysfatal("exec rc: %r");
          656         }
          657 
          658         close(pip[1]);
          659         pushfd(pip[0]);
          660 
          661         isave = interactive;
          662         interactive = 0;
          663         r->store.u.ival = yyparse();
          664         interactive = isave;
          665         popio();
          666 
          667         r->op = OCONST;
          668         r->type = TINT;
          669         r->store.fmt = 'D';
          670 
          671         w = waitfor(pid);
          672         if(w->msg && w->msg[0])
          673                 error("includepipe(\"%s\"): %s", argv[2], w->msg);        /* leaks w */
          674         free(w);
          675 }
          676 
          677 void
          678 rc(Node *r, Node *args)
          679 {
          680         Node res;
          681         int pid;
          682         char *p, *q, *argv[4];
          683         Waitmsg *w;
          684 
          685         USED(r);
          686         if(args == 0)
          687                 error("rc(string): arg count");
          688         expr(args, &res);
          689         if(res.type != TSTRING)
          690                 error("rc(string): arg type");
          691 
          692         argv[0] = "rc";
          693         argv[1] = "-c";
          694         argv[2] = res.store.u.string->string;
          695         argv[3] = 0;
          696 
          697         pid = fork();
          698         switch(pid) {
          699         case -1:
          700                 error("fork %r");
          701         case 0:
          702                 exec("rc", argv);
          703                 exits(0);
          704         default:
          705                 w = waitfor(pid);
          706                 break;
          707         }
          708         p = w->msg;
          709         q = strrchr(p, ':');
          710         if (q)
          711                 p = q+1;
          712 
          713         r->op = OCONST;
          714         r->type = TSTRING;
          715         r->store.u.string = strnode(p);
          716         free(w);
          717         r->store.fmt = 's';
          718 }
          719 
          720 void
          721 doerror(Node *r, Node *args)
          722 {
          723         Node res;
          724 
          725         USED(r);
          726         if(args == 0)
          727                 error("error(string): arg count");
          728         expr(args, &res);
          729         if(res.type != TSTRING)
          730                 error("error(string): arg type");
          731 
          732         error(res.store.u.string->string);
          733 }
          734 
          735 void
          736 doaccess(Node *r, Node *args)
          737 {
          738         Node res;
          739 
          740         if(args == 0)
          741                 error("access(filename): arg count");
          742         expr(args, &res);
          743         if(res.type != TSTRING)
          744                 error("access(filename): arg type");
          745 
          746         r->op = OCONST;
          747         r->type = TINT;
          748         r->store.fmt = 'D';
          749         r->store.u.ival = 0;
          750         if(access(res.store.u.string->string, 4) == 0)
          751                 r->store.u.ival = 1;
          752 }
          753 
          754 void
          755 readfile(Node *r, Node *args)
          756 {
          757         Node res;
          758         int n, fd;
          759         char *buf;
          760         Dir *db;
          761 
          762         if(args == 0)
          763                 error("readfile(filename): arg count");
          764         expr(args, &res);
          765         if(res.type != TSTRING)
          766                 error("readfile(filename): arg type");
          767 
          768         fd = open(res.store.u.string->string, OREAD);
          769         if(fd < 0)
          770                 return;
          771 
          772         db = dirfstat(fd);
          773         if(db == nil || db->length == 0)
          774                 n = 8192;
          775         else
          776                 n = db->length;
          777         free(db);
          778 
          779         buf = malloc(n);
          780         n = read(fd, buf, n);
          781 
          782         if(n > 0) {
          783                 r->op = OCONST;
          784                 r->type = TSTRING;
          785                 r->store.u.string = strnodlen(buf, n);
          786                 r->store.fmt = 's';
          787         }
          788         free(buf);
          789         close(fd);
          790 }
          791 
          792 void
          793 getfile(Node *r, Node *args)
          794 {
          795         int n;
          796         char *p;
          797         Node res;
          798         String *s;
          799         Biobuf *bp;
          800         List **l, *new;
          801 
          802         if(args == 0)
          803                 error("file(filename): arg count");
          804         expr(args, &res);
          805         if(res.type != TSTRING)
          806                 error("file(filename): arg type");
          807 
          808         r->op = OCONST;
          809         r->type = TLIST;
          810         r->store.u.l = 0;
          811 
          812         p = res.store.u.string->string;
          813         bp = Bopen(p, OREAD);
          814         if(bp == 0)
          815                 return;
          816 
          817         l = &r->store.u.l;
          818         for(;;) {
          819                 p = Brdline(bp, '\n');
          820                 n = Blinelen(bp);
          821                 if(p == 0) {
          822                         if(n == 0)
          823                                 break;
          824                         s = strnodlen(0, n);
          825                         Bread(bp, s->string, n);
          826                 }
          827                 else
          828                         s = strnodlen(p, n-1);
          829 
          830                 new = al(TSTRING);
          831                 new->store.u.string = s;
          832                 new->store.fmt = 's';
          833                 *l = new;
          834                 l = &new->next;
          835         }
          836         Bterm(bp);
          837 }
          838 
          839 void
          840 cvtatof(Node *r, Node *args)
          841 {
          842         Node res;
          843 
          844         if(args == 0)
          845                 error("atof(string): arg count");
          846         expr(args, &res);
          847         if(res.type != TSTRING)
          848                 error("atof(string): arg type");
          849 
          850         r->op = OCONST;
          851         r->type = TFLOAT;
          852         r->store.u.fval = atof(res.store.u.string->string);
          853         r->store.fmt = 'f';
          854 }
          855 
          856 void
          857 cvtatoi(Node *r, Node *args)
          858 {
          859         Node res;
          860 
          861         if(args == 0)
          862                 error("atoi(string): arg count");
          863         expr(args, &res);
          864         if(res.type != TSTRING)
          865                 error("atoi(string): arg type");
          866 
          867         r->op = OCONST;
          868         r->type = TINT;
          869         r->store.u.ival = strtoull(res.store.u.string->string, 0, 0);
          870         r->store.fmt = 'D';
          871 }
          872 
          873 void
          874 cvtitoa(Node *r, Node *args)
          875 {
          876         Node res;
          877         Node *av[Maxarg];
          878         s64int ival;
          879         char buf[128], *fmt;
          880 
          881         if(args == 0)
          882 err:
          883                 error("itoa(number [, printformat]): arg count");
          884         na = 0;
          885         flatten(av, args);
          886         if(na == 0 || na > 2)
          887                 goto err;
          888         expr(av[0], &res);
          889         if(res.type != TINT)
          890                 error("itoa(integer): arg type");
          891         ival = (int)res.store.u.ival;
          892         fmt = "%d";
          893         if(na == 2){
          894                 expr(av[1], &res);
          895                 if(res.type != TSTRING)
          896                         error("itoa(integer, string): arg type");
          897                 fmt = res.store.u.string->string;
          898         }
          899 
          900         sprint(buf, fmt, ival);
          901         r->op = OCONST;
          902         r->type = TSTRING;
          903         r->store.u.string = strnode(buf);
          904         r->store.fmt = 's';
          905 }
          906 
          907 List*
          908 mapent(Map *m)
          909 {
          910         int i;
          911         List *l, *n, **t, *h;
          912 
          913         h = 0;
          914         t = &h;
          915         for(i = 0; i < m->nseg; i++) {
          916                 l = al(TSTRING);
          917                 n = al(TLIST);
          918                 n->store.u.l = l;
          919                 *t = n;
          920                 t = &n->next;
          921                 l->store.u.string = strnode(m->seg[i].name);
          922                 l->store.fmt = 's';
          923                 l->next = al(TSTRING);
          924                 l = l->next;
          925                 l->store.u.string = strnode(m->seg[i].file ? m->seg[i].file : "");
          926                 l->store.fmt = 's';
          927                 l->next = al(TINT);
          928                 l = l->next;
          929                 l->store.u.ival = m->seg[i].base;
          930                 l->store.fmt = 'X';
          931                 l->next = al(TINT);
          932                 l = l->next;
          933                 l->store.u.ival = m->seg[i].base + m->seg[i].size;
          934                 l->store.fmt = 'X';
          935                 l->next = al(TINT);
          936                 l = l->next;
          937                 l->store.u.ival = m->seg[i].offset;
          938                 l->store.fmt = 'X';
          939         }
          940         return h;
          941 }
          942 
          943 void
          944 map(Node *r, Node *args)
          945 {
          946         int i;
          947         Map *m;
          948         List *l;
          949         char *nam, *fil;
          950         Node *av[Maxarg], res;
          951 
          952         na = 0;
          953         flatten(av, args);
          954 
          955         if(na != 0) {
          956                 expr(av[0], &res);
          957                 if(res.type != TLIST)
          958                         error("map(list): map needs a list");
          959                 if(listlen(res.store.u.l) != 5)
          960                         error("map(list): list must have 5 entries");
          961 
          962                 l = res.store.u.l;
          963                 if(l->type != TSTRING)
          964                         error("map name must be a string");
          965                 nam = l->store.u.string->string;
          966                 l = l->next;
          967                 if(l->type != TSTRING)
          968                         error("map file must be a string");
          969                 fil = l->store.u.string->string;
          970                 m = symmap;
          971                 i = findseg(m, nam, fil);
          972                 if(i < 0) {
          973                         m = cormap;
          974                         i = findseg(m, nam, fil);
          975                 }
          976                 if(i < 0)
          977                         error("%s %s is not a map entry", nam, fil);
          978                 l = l->next;
          979                 if(l->type != TINT)
          980                         error("map entry not int");
          981                 m->seg[i].base = l->store.u.ival;
          982 /*
          983                 if (strcmp(ent, "text") == 0)
          984                         textseg(l->store.u.ival, &fhdr);
          985 */
          986                 l = l->next;
          987                 if(l->type != TINT)
          988                         error("map entry not int");
          989                 m->seg[i].size = l->store.u.ival - m->seg[i].base;
          990                 l = l->next;
          991                 if(l->type != TINT)
          992                         error("map entry not int");
          993                 m->seg[i].offset = l->store.u.ival;
          994         }
          995 
          996         r->type = TLIST;
          997         r->store.u.l = 0;
          998         if(symmap)
          999                 r->store.u.l = mapent(symmap);
         1000         if(cormap) {
         1001                 if(r->store.u.l == 0)
         1002                         r->store.u.l = mapent(cormap);
         1003                 else {
         1004                         for(l = r->store.u.l; l->next; l = l->next)
         1005                                 ;
         1006                         l->next = mapent(cormap);
         1007                 }
         1008         }
         1009 }
         1010 
         1011 void
         1012 flatten(Node **av, Node *n)
         1013 {
         1014         if(n == 0)
         1015                 return;
         1016 
         1017         switch(n->op) {
         1018         case OLIST:
         1019                 flatten(av, n->left);
         1020                 flatten(av, n->right);
         1021                 break;
         1022         default:
         1023                 av[na++] = n;
         1024                 if(na >= Maxarg)
         1025                         error("too many function arguments");
         1026                 break;
         1027         }
         1028 }
         1029 
         1030 static struct
         1031 {
         1032         char *name;
         1033         u64int val;
         1034 } sregs[Maxarg/2];
         1035 static int nsregs;
         1036 
         1037 static int
         1038 straceregrw(Regs *regs, char *name, u64int *val, int isr)
         1039 {
         1040         int i;
         1041 
         1042         if(!isr){
         1043                 werrstr("saved registers cannot be written");
         1044                 return -1;
         1045         }
         1046         for(i=0; i<nsregs; i++)
         1047                 if(strcmp(sregs[i].name, name) == 0){
         1048                         *val = sregs[i].val;
         1049                         return 0;
         1050                 }
         1051         return rget(acidregs, name, val);
         1052 }
         1053 
         1054 void
         1055 strace(Node *r, Node *args)
         1056 {
         1057         Node *av[Maxarg], res;
         1058         List *l;
         1059         Regs regs;
         1060 
         1061         na = 0;
         1062         flatten(av, args);
         1063 
         1064         if(na != 1)
         1065                 error("strace(list): want one arg");
         1066 
         1067         expr(av[0], &res);
         1068         if(res.type != TLIST)
         1069                 error("strace(list): strace needs a list");
         1070         l = res.store.u.l;
         1071         if(listlen(l)%2)
         1072                 error("strace(list): strace needs an even-length list");
         1073         for(nsregs=0; l; nsregs++){
         1074                 if(l->type != TSTRING)
         1075                         error("strace({r,v,r,v,...}): non-string name");
         1076                 sregs[nsregs].name = l->store.u.string->string;
         1077                 if(regdesc(sregs[nsregs].name) == nil)
         1078                         error("strace: bad register '%s'", sregs[nsregs].name);
         1079                 l = l->next;
         1080 
         1081                 if(l == nil)
         1082                         error("cannot happen in strace");
         1083                 if(l->type != TINT)
         1084                         error("strace: non-int value for %s", sregs[nsregs].name);
         1085                 sregs[nsregs].val = l->store.u.ival;
         1086                 l = l->next;
         1087         }
         1088         regs.rw = straceregrw;
         1089 
         1090         tracelist = 0;
         1091         if(stacktrace(cormap, &regs, trlist) <= 0)
         1092                 error("no stack frame");
         1093         r->type = TLIST;
         1094         r->store.u.l = tracelist;
         1095 }
         1096 
         1097 void
         1098 regerror(char *msg)
         1099 {
         1100         error(msg);
         1101 }
         1102 
         1103 void
         1104 regexp(Node *r, Node *args)
         1105 {
         1106         Node res;
         1107         Reprog *rp;
         1108         Node *av[Maxarg];
         1109 
         1110         na = 0;
         1111         flatten(av, args);
         1112         if(na != 2)
         1113                 error("regexp(pattern, string): arg count");
         1114         expr(av[0], &res);
         1115         if(res.type != TSTRING)
         1116                 error("regexp(pattern, string): pattern must be string");
         1117         rp = regcomp(res.store.u.string->string);
         1118         if(rp == 0)
         1119                 return;
         1120 
         1121         expr(av[1], &res);
         1122         if(res.type != TSTRING)
         1123                 error("regexp(pattern, string): bad string");
         1124 
         1125         r->store.fmt = 'D';
         1126         r->type = TINT;
         1127         r->store.u.ival = regexec(rp, res.store.u.string->string, 0, 0);
         1128         free(rp);
         1129 }
         1130 
         1131 char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVxXYZ";
         1132 
         1133 void
         1134 fmt(Node *r, Node *args)
         1135 {
         1136         Node res;
         1137         Node *av[Maxarg];
         1138 
         1139         na = 0;
         1140         flatten(av, args);
         1141         if(na != 2)
         1142                 error("fmt(obj, fmt): arg count");
         1143         expr(av[1], &res);
         1144         if(res.type != TINT || strchr(vfmt, res.store.u.ival) == 0)
         1145                 error("fmt(obj, fmt): bad format '%c'", (char)res.store.u.ival);
         1146         expr(av[0], r);
         1147         r->store.fmt = res.store.u.ival;
         1148 }
         1149 
         1150 void
         1151 patom(char type, Store *res)
         1152 {
         1153         int i;
         1154         char buf[512];
         1155         extern char *typenames[];
         1156         Node *n;
         1157 
         1158         switch(type){
         1159         case TREG:
         1160                 if(res->u.reg.thread)
         1161                         Bprint(bout, "register(\"%s\", %#ux)", res->u.reg.name, res->u.reg.thread);
         1162                 else
         1163                         Bprint(bout, "register(\"%s\")", res->u.reg.name);
         1164                 return;
         1165         case TCON:
         1166                 Bprint(bout, "refconst(");
         1167                 n = res->u.con;
         1168                 patom(n->type, &n->store);
         1169                 Bprint(bout, ")");
         1170                 return;
         1171         }
         1172 
         1173         switch(res->fmt){
         1174         case 'c':
         1175         case 'C':
         1176         case 'r':
         1177         case 'B':
         1178         case 'b':
         1179         case 'X':
         1180         case 'x':
         1181         case 'W':
         1182         case 'D':
         1183         case 'd':
         1184         case 'u':
         1185         case 'U':
         1186         case 'Z':
         1187         case 'V':
         1188         case 'Y':
         1189         case 'o':
         1190         case 'O':
         1191         case 'q':
         1192         case 'Q':
         1193         case 'a':
         1194         case 'A':
         1195         case 'I':
         1196         case 'i':
         1197                 if(type != TINT){
         1198                 badtype:
         1199                         Bprint(bout, "*%s\\%c*", typenames[(uchar)type], res->fmt);
         1200                         return;
         1201                 }
         1202                 break;
         1203 
         1204         case 'f':
         1205         case 'F':
         1206                 if(type != TFLOAT)
         1207                         goto badtype;
         1208                 break;
         1209 
         1210         case 's':
         1211         case 'g':
         1212         case 'G':
         1213         case 'R':
         1214                 if(type != TSTRING)
         1215                         goto badtype;
         1216                 break;
         1217         }
         1218 
         1219         switch(res->fmt) {
         1220         case 'c':
         1221                 Bprint(bout, "%c", (int)res->u.ival);
         1222                 break;
         1223         case 'C':
         1224                 if(res->u.ival < ' ' || res->u.ival >= 0x7f)
         1225                         Bprint(bout, "%3d", (int)res->u.ival&0xff);
         1226                 else
         1227                         Bprint(bout, "%3c", (int)res->u.ival);
         1228                 break;
         1229         case 'r':
         1230                 Bprint(bout, "%C", (int)res->u.ival);
         1231                 break;
         1232         case 'B':
         1233                 memset(buf, '0', 34);
         1234                 buf[1] = 'b';
         1235                 for(i = 0; i < 32; i++) {
         1236                         if(res->u.ival & (1<<i))
         1237                                 buf[33-i] = '1';
         1238                 }
         1239                 buf[35] = '\0';
         1240                 Bprint(bout, "%s", buf);
         1241                 break;
         1242         case 'b':
         1243                 Bprint(bout, "%#.2x", (int)res->u.ival&0xff);
         1244                 break;
         1245         case 'X':
         1246                 Bprint(bout, "%#.8lux", (ulong)res->u.ival);
         1247                 break;
         1248         case 'x':
         1249                 Bprint(bout, "%#.4lux", (ulong)res->u.ival&0xffff);
         1250                 break;
         1251         case 'W':
         1252                 Bprint(bout, "%#.16llux", res->u.ival);
         1253                 break;
         1254         case 'D':
         1255                 Bprint(bout, "%d", (int)res->u.ival);
         1256                 break;
         1257         case 'd':
         1258                 Bprint(bout, "%d", (ushort)res->u.ival);
         1259                 break;
         1260         case 'u':
         1261                 Bprint(bout, "%d", (int)res->u.ival&0xffff);
         1262                 break;
         1263         case 'U':
         1264                 Bprint(bout, "%lud", (ulong)res->u.ival);
         1265                 break;
         1266         case 'Z':
         1267                 Bprint(bout, "%llud", res->u.ival);
         1268                 break;
         1269         case 'V':
         1270                 Bprint(bout, "%lld", res->u.ival);
         1271                 break;
         1272         case 'Y':
         1273                 Bprint(bout, "%#.16llux", res->u.ival);
         1274                 break;
         1275         case 'o':
         1276                 Bprint(bout, "%#.11uo", (int)res->u.ival&0xffff);
         1277                 break;
         1278         case 'O':
         1279                 Bprint(bout, "%#.6uo", (int)res->u.ival);
         1280                 break;
         1281         case 'q':
         1282                 Bprint(bout, "%#.11o", (short)(res->u.ival&0xffff));
         1283                 break;
         1284         case 'Q':
         1285                 Bprint(bout, "%#.6o", (int)res->u.ival);
         1286                 break;
         1287         case 'f':
         1288         case 'F':
         1289                 Bprint(bout, "%g", res->u.fval);
         1290                 break;
         1291         case 's':
         1292         case 'g':
         1293         case 'G':
         1294                 Bwrite(bout, res->u.string->string, res->u.string->len);
         1295                 break;
         1296         case 'R':
         1297                 Bprint(bout, "%S", (Rune*)res->u.string->string);
         1298                 break;
         1299         case 'a':
         1300         case 'A':
         1301                 symoff(buf, sizeof(buf), res->u.ival, CANY);
         1302                 Bprint(bout, "%s", buf);
         1303                 break;
         1304         case 'I':
         1305         case 'i':
         1306                 if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
         1307                         Bprint(bout, "no instruction");
         1308                 else
         1309                         Bprint(bout, "%s", buf);
         1310                 break;
         1311         }
         1312 }
         1313 
         1314 void
         1315 blprint(List *l)
         1316 {
         1317         Store *res;
         1318 
         1319         Bprint(bout, "{");
         1320         while(l) {
         1321                 switch(l->type) {
         1322                 case TINT:
         1323                         res = &l->store;
         1324                         if(res->fmt == 'c'){
         1325                                 Bprint(bout, "\'%c\'", (int)res->u.ival);
         1326                                 break;
         1327                         }else if(res->fmt == 'r'){
         1328                                 Bprint(bout, "\'%C\'", (int)res->u.ival);
         1329                                 break;
         1330                         }
         1331                         /* fall through */
         1332                 default:
         1333                         patom(l->type, &l->store);
         1334                         break;
         1335                 case TSTRING:
         1336                         Bputc(bout, '"');
         1337                         patom(l->type, &l->store);
         1338                         Bputc(bout, '"');
         1339                         break;
         1340                 case TLIST:
         1341                         blprint(l->store.u.l);
         1342                         break;
         1343                 case TCODE:
         1344                         pcode(l->store.u.cc, 0);
         1345                         break;
         1346                 }
         1347                 l = l->next;
         1348                 if(l)
         1349                         Bprint(bout, ", ");
         1350         }
         1351         Bprint(bout, "}");
         1352 }
         1353 
         1354 int
         1355 comx(Node res)
         1356 {
         1357         Lsym *sl;
         1358         Node *n, xx;
         1359 
         1360         if(res.store.fmt != 'a' && res.store.fmt != 'A')
         1361                 return 0;
         1362 
         1363         if(res.store.comt == 0 || res.store.comt->base == 0)
         1364                 return 0;
         1365 
         1366         sl = res.store.comt->base;
         1367         if(sl->proc) {
         1368                 res.left = ZN;
         1369                 res.right = ZN;
         1370                 n = an(ONAME, ZN, ZN);
         1371                 n->sym = sl;
         1372                 n = an(OCALL, n, &res);
         1373                         n->left->sym = sl;
         1374                 expr(n, &xx);
         1375                 return 1;
         1376         }
         1377         print("(%s)", sl->name);
         1378         return 0;
         1379 }
         1380 
         1381 void
         1382 bprint(Node *r, Node *args)
         1383 {
         1384         int i, nas;
         1385         Node res, *av[Maxarg];
         1386 
         1387         USED(r);
         1388         na = 0;
         1389         flatten(av, args);
         1390         nas = na;
         1391         for(i = 0; i < nas; i++) {
         1392                 expr(av[i], &res);
         1393                 switch(res.type) {
         1394                 default:
         1395                         if(comx(res))
         1396                                 break;
         1397                         patom(res.type, &res.store);
         1398                         break;
         1399                 case TCODE:
         1400                         pcode(res.store.u.cc, 0);
         1401                         break;
         1402                 case TLIST:
         1403                         blprint(res.store.u.l);
         1404                         break;
         1405                 }
         1406         }
         1407         if(ret == 0)
         1408                 Bputc(bout, '\n');
         1409 }
         1410 
         1411 void
         1412 printto(Node *r, Node *args)
         1413 {
         1414         int fd;
         1415         Biobuf *b;
         1416         int i, nas;
         1417         Node res, *av[Maxarg];
         1418 
         1419         USED(r);
         1420         na = 0;
         1421         flatten(av, args);
         1422         nas = na;
         1423 
         1424         expr(av[0], &res);
         1425         if(res.type != TSTRING)
         1426                 error("printto(string, ...): need string");
         1427 
         1428         fd = create(res.store.u.string->string, OWRITE, 0666);
         1429         if(fd < 0)
         1430                 fd = open(res.store.u.string->string, OWRITE);
         1431         if(fd < 0)
         1432                 error("printto: open %s: %r", res.store.u.string->string);
         1433 
         1434         b = gmalloc(sizeof(Biobuf));
         1435         Binit(b, fd, OWRITE);
         1436 
         1437         Bflush(bout);
         1438         io[iop++] = bout;
         1439         bout = b;
         1440 
         1441         for(i = 1; i < nas; i++) {
         1442                 expr(av[i], &res);
         1443                 switch(res.type) {
         1444                 default:
         1445                         if(comx(res))
         1446                                 break;
         1447                         patom(res.type, &res.store);
         1448                         break;
         1449                 case TLIST:
         1450                         blprint(res.store.u.l);
         1451                         break;
         1452                 }
         1453         }
         1454         if(ret == 0)
         1455                 Bputc(bout, '\n');
         1456 
         1457         Bterm(b);
         1458         close(fd);
         1459         free(b);
         1460         bout = io[--iop];
         1461 }
         1462 
         1463 void
         1464 pcfile(Node *r, Node *args)
         1465 {
         1466         Node res;
         1467         char *p, buf[128];
         1468 
         1469         if(args == 0)
         1470                 error("pcfile(addr): arg count");
         1471         expr(args, &res);
         1472         if(res.type != TINT)
         1473                 error("pcfile(addr): arg type");
         1474 
         1475         r->type = TSTRING;
         1476         r->store.fmt = 's';
         1477         if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
         1478                 r->store.u.string = strnode("?file?");
         1479                 return;
         1480         }
         1481         p = strrchr(buf, ':');
         1482         if(p == 0)
         1483                 error("pcfile(addr): funny file %s", buf);
         1484         *p = '\0';
         1485         r->store.u.string = strnode(buf);
         1486 }
         1487 
         1488 void
         1489 pcline(Node *r, Node *args)
         1490 {
         1491         Node res;
         1492         char *p, buf[128];
         1493 
         1494         if(args == 0)
         1495                 error("pcline(addr): arg count");
         1496         expr(args, &res);
         1497         if(res.type != TINT)
         1498                 error("pcline(addr): arg type");
         1499 
         1500         r->type = TINT;
         1501         r->store.fmt = 'D';
         1502         if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
         1503                 r->store.u.ival = 0;
         1504                 return;
         1505         }
         1506 
         1507         p = strrchr(buf, ':');
         1508         if(p == 0)
         1509                 error("pcline(addr): funny file %s", buf);
         1510         r->store.u.ival = atoi(p+1);
         1511 }
         1512 
         1513 void
         1514 textfile(Node *r, Node *args)
         1515 {
         1516         char *file;
         1517         long base;
         1518         Fhdr *fp;
         1519         Node res, *av[Maxarg];
         1520         List *l, *l2, **tail, *list, *tl;
         1521 
         1522         na = 0;
         1523         flatten(av, args);
         1524 
         1525         if(na != 0) {
         1526                 expr(av[0], &res);
         1527                 if(res.type != TLIST)
         1528                         error("textfile(list): textfile needs a list");
         1529                 if(listlen(res.store.u.l) != 2)
         1530                         error("textfile(list): list must have 2 entries");
         1531 
         1532                 l = res.store.u.l;
         1533                 if(l->type != TSTRING)
         1534                         error("textfile name must be a string");
         1535                 file = l->store.u.string->string;
         1536 
         1537                 l = l->next;
         1538                 if(l->type != TINT)
         1539                         error("textfile base must be an int");
         1540                 base = l->store.u.ival;
         1541 
         1542                 if((fp = crackhdr(file, OREAD)) == nil)
         1543                         error("crackhdr %s: %r", file);
         1544                 Bflush(bout);
         1545                 fp->base = base;
         1546                 fprint(2, "%s: %s %s %s\n", file, fp->aname, fp->mname, fp->fname);
         1547                 if(mapfile(fp, base, symmap, nil) < 0)
         1548                         fprint(2, "mapping %s: %r\n", file);
         1549                 if(corhdr){
         1550                         unmapfile(corhdr, cormap);
         1551                         mapfile(fp, base, cormap, nil);
         1552                         free(correg);
         1553                         correg = nil;
         1554                         mapfile(corhdr, 0, cormap, &correg);
         1555                 }
         1556                 if(symopen(fp) < 0)
         1557                         fprint(2, "symopen %s: %r\n", file);
         1558                 else
         1559                         addvarsym(fp);
         1560                 return;
         1561         }
         1562 
         1563         l2 = nil;
         1564         tail = &l2;
         1565         for(fp=fhdrlist; fp; fp=fp->next){
         1566                 if(fp->ftype == FCORE)
         1567                         continue;
         1568                 tl = al(TLIST);
         1569                 *tail = tl;
         1570                 tail = &tl->next;
         1571 
         1572                 list = al(TSTRING);
         1573                 tl->store.u.l = list;
         1574                 list->store.u.string = strnode(fp->filename);
         1575                 list->store.fmt = 's';
         1576                 list->next = al(TINT);
         1577                 list = list->next;
         1578                 list->store.fmt = 'X';
         1579                 list->store.u.ival = fp->base;
         1580         }
         1581 
         1582         r->type = TLIST;
         1583         r->store.u.l = l2;
         1584 }
         1585 
         1586 void
         1587 deltextfile(Node *r, Node *args)
         1588 {
         1589         int did;
         1590         char *file;
         1591         Fhdr *fp, *fpnext;
         1592         Node res, *av[Maxarg];
         1593 
         1594         na = 0;
         1595         flatten(av, args);
         1596 
         1597         if(na != 1)
         1598                 error("deltextfile(string): arg count");
         1599 
         1600         expr(av[0], &res);
         1601         if(res.type != TSTRING)
         1602                 error("deltextfile(string): arg type");
         1603         file = res.store.u.string->string;
         1604 
         1605         did = 0;
         1606         for(fp=fhdrlist; fp; fp=fpnext){
         1607                 fpnext = fp->next;
         1608                 if(fp->ftype == FCORE)
         1609                         continue;
         1610                 if(strcmp(file, fp->filename) == 0){
         1611                         did = 1;
         1612                         if(fp == symhdr)
         1613                                 error("cannot remove symbols from main text file");
         1614                         unmapfile(fp, symmap);
         1615                         uncrackhdr(fp);
         1616                 }
         1617         }
         1618 
         1619         delvarsym(file);
         1620         if(!did)
         1621                 error("symbol file %s not open", file);
         1622 }
         1623 
         1624 void
         1625 stringn(Node *r, Node *args)
         1626 {
         1627         uint addr;
         1628         int i, n, ret;
         1629         Node res, *av[Maxarg];
         1630         char *buf;
         1631 
         1632         na = 0;
         1633         flatten(av, args);
         1634         if(na != 2)
         1635                 error("stringn(addr, n): arg count");
         1636 
         1637         expr(av[0], &res);
         1638         if(res.type != TINT)
         1639                 error("stringn(addr, n): arg type");
         1640         addr = res.store.u.ival;
         1641 
         1642         expr(av[1], &res);
         1643         if(res.type != TINT)
         1644                 error("stringn(addr,n): arg type");
         1645         n = res.store.u.ival;
         1646 
         1647         buf = malloc(n+1);
         1648         if(buf == nil)
         1649                 error("out of memory");
         1650 
         1651         r->type = TSTRING;
         1652         for(i=0; i<n; i++){
         1653                 ret = get1(cormap, addr, (uchar*)&buf[i], 1);
         1654                 if(ret < 0){
         1655                         free(buf);
         1656                         error("indir: %r");
         1657                 }
         1658                 addr++;
         1659         }
         1660         buf[n] = 0;
         1661         r->store.u.string = strnode(buf);
         1662         free(buf);
         1663 }