1 /*
2 * This file was generated by the mknodes program.
3 */
4
5 /*-
6 * Copyright (c) 1991, 1993
7 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2005
9 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
10 *
11 * This code is derived from software contributed to Berkeley by
12 * Kenneth Almquist.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
39 */
40
41 #include <zircon/syscalls.h>
42 #include <stdlib.h>
43
44 /*
45 * Routine for dealing with parsed shell commands.
46 */
47
48 #include "shell.h"
49 #include "nodes.h"
50 #include "memalloc.h"
51 #include "machdep.h"
52 #include "mystring.h"
53 #include "system.h"
54 #include "error.h"
55 #include "var.h"
56
57
58 int funcblocksize; /* size of structures in function */
59 int funcstringsize; /* size of strings in node */
60 pointer funcblock; /* block to allocate function from */
61 char *funcstring; /* block to allocate strings from */
62
63 static const short nodesize[26] = {
64 SHELL_ALIGN(sizeof (struct ncmd)),
65 SHELL_ALIGN(sizeof (struct npipe)),
66 SHELL_ALIGN(sizeof (struct nredir)),
67 SHELL_ALIGN(sizeof (struct nredir)),
68 SHELL_ALIGN(sizeof (struct nredir)),
69 SHELL_ALIGN(sizeof (struct nbinary)),
70 SHELL_ALIGN(sizeof (struct nbinary)),
71 SHELL_ALIGN(sizeof (struct nbinary)),
72 SHELL_ALIGN(sizeof (struct nif)),
73 SHELL_ALIGN(sizeof (struct nbinary)),
74 SHELL_ALIGN(sizeof (struct nbinary)),
75 SHELL_ALIGN(sizeof (struct nfor)),
76 SHELL_ALIGN(sizeof (struct ncase)),
77 SHELL_ALIGN(sizeof (struct nclist)),
78 SHELL_ALIGN(sizeof (struct ndefun)),
79 SHELL_ALIGN(sizeof (struct narg)),
80 SHELL_ALIGN(sizeof (struct nfile)),
81 SHELL_ALIGN(sizeof (struct nfile)),
82 SHELL_ALIGN(sizeof (struct nfile)),
83 SHELL_ALIGN(sizeof (struct nfile)),
84 SHELL_ALIGN(sizeof (struct nfile)),
85 SHELL_ALIGN(sizeof (struct ndup)),
86 SHELL_ALIGN(sizeof (struct ndup)),
87 SHELL_ALIGN(sizeof (struct nhere)),
88 SHELL_ALIGN(sizeof (struct nhere)),
89 SHELL_ALIGN(sizeof (struct nnot)),
90 };
91
92
93 STATIC void calcsize(union node *);
94 STATIC void sizenodelist(struct nodelist *);
95 STATIC union node *copynode(union node *);
96 STATIC struct nodelist *copynodelist(struct nodelist *);
97 STATIC char *nodesavestr(char *);
98
99 STATIC void writenode(union node *n, size_t node_size, size_t block_size);
100 STATIC void encodenode(union node *);
101 STATIC void encodenodelist(struct nodelist *);
102 STATIC void encodestring(const char *);
103
104 STATIC void decodenode(union node **);
105 STATIC void decodenodelist(struct nodelist **);
106 STATIC char *decodestring();
107
108 /*
109 * Make a copy of a parse tree.
110 */
111
112 struct funcnode *
copyfunc(union node * n)113 copyfunc(union node *n)
114 {
115 struct funcnode *f;
116 size_t blocksize;
117
118 funcblocksize = offsetof(struct funcnode, n);
119 funcstringsize = 0;
120 calcsize(n);
121 blocksize = funcblocksize;
122 f = ckmalloc(blocksize + funcstringsize);
123 funcblock = (char *) f + offsetof(struct funcnode, n);
124 funcstring = (char *) f + blocksize;
125 copynode(n);
126 f->count = 0;
127 return f;
128 }
129
130
131
132 STATIC void
calcsize(n)133 calcsize(n)
134 union node *n;
135 {
136 if (n == NULL)
137 return;
138 funcblocksize += nodesize[n->type];
139 switch (n->type) {
140 case NCMD:
141 calcsize(n->ncmd.redirect);
142 calcsize(n->ncmd.args);
143 calcsize(n->ncmd.assign);
144 break;
145 case NPIPE:
146 sizenodelist(n->npipe.cmdlist);
147 break;
148 case NREDIR:
149 case NBACKGND:
150 case NSUBSHELL:
151 calcsize(n->nredir.redirect);
152 calcsize(n->nredir.n);
153 break;
154 case NAND:
155 case NOR:
156 case NSEMI:
157 case NWHILE:
158 case NUNTIL:
159 calcsize(n->nbinary.ch2);
160 calcsize(n->nbinary.ch1);
161 break;
162 case NIF:
163 calcsize(n->nif.elsepart);
164 calcsize(n->nif.ifpart);
165 calcsize(n->nif.test);
166 break;
167 case NFOR:
168 funcstringsize += strlen(n->nfor.var) + 1;
169 calcsize(n->nfor.body);
170 calcsize(n->nfor.args);
171 break;
172 case NCASE:
173 calcsize(n->ncase.cases);
174 calcsize(n->ncase.expr);
175 break;
176 case NCLIST:
177 calcsize(n->nclist.body);
178 calcsize(n->nclist.pattern);
179 calcsize(n->nclist.next);
180 break;
181 case NDEFUN:
182 calcsize(n->ndefun.body);
183 funcstringsize += strlen(n->ndefun.text) + 1;
184 break;
185 case NARG:
186 sizenodelist(n->narg.backquote);
187 funcstringsize += strlen(n->narg.text) + 1;
188 calcsize(n->narg.next);
189 break;
190 case NTO:
191 case NCLOBBER:
192 case NFROM:
193 case NFROMTO:
194 case NAPPEND:
195 calcsize(n->nfile.fname);
196 calcsize(n->nfile.next);
197 break;
198 case NTOFD:
199 case NFROMFD:
200 calcsize(n->ndup.vname);
201 calcsize(n->ndup.next);
202 break;
203 case NHERE:
204 case NXHERE:
205 calcsize(n->nhere.doc);
206 calcsize(n->nhere.next);
207 break;
208 case NNOT:
209 calcsize(n->nnot.com);
210 break;
211 };
212 }
213
214
215
216 STATIC void
sizenodelist(lp)217 sizenodelist(lp)
218 struct nodelist *lp;
219 {
220 while (lp) {
221 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
222 calcsize(lp->n);
223 lp = lp->next;
224 }
225 }
226
227
228
229 STATIC union node *
copynode(n)230 copynode(n)
231 union node *n;
232 {
233 union node *new;
234
235 if (n == NULL)
236 return NULL;
237 new = funcblock;
238 funcblock = (char *) funcblock + nodesize[n->type];
239 switch (n->type) {
240 case NCMD:
241 new->ncmd.redirect = copynode(n->ncmd.redirect);
242 new->ncmd.args = copynode(n->ncmd.args);
243 new->ncmd.assign = copynode(n->ncmd.assign);
244 new->ncmd.linno = n->ncmd.linno;
245 break;
246 case NPIPE:
247 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
248 new->npipe.backgnd = n->npipe.backgnd;
249 break;
250 case NREDIR:
251 case NBACKGND:
252 case NSUBSHELL:
253 new->nredir.redirect = copynode(n->nredir.redirect);
254 new->nredir.n = copynode(n->nredir.n);
255 new->nredir.linno = n->nredir.linno;
256 break;
257 case NAND:
258 case NOR:
259 case NSEMI:
260 case NWHILE:
261 case NUNTIL:
262 new->nbinary.ch2 = copynode(n->nbinary.ch2);
263 new->nbinary.ch1 = copynode(n->nbinary.ch1);
264 break;
265 case NIF:
266 new->nif.elsepart = copynode(n->nif.elsepart);
267 new->nif.ifpart = copynode(n->nif.ifpart);
268 new->nif.test = copynode(n->nif.test);
269 break;
270 case NFOR:
271 new->nfor.var = nodesavestr(n->nfor.var);
272 new->nfor.body = copynode(n->nfor.body);
273 new->nfor.args = copynode(n->nfor.args);
274 new->nfor.linno = n->nfor.linno;
275 break;
276 case NCASE:
277 new->ncase.cases = copynode(n->ncase.cases);
278 new->ncase.expr = copynode(n->ncase.expr);
279 new->ncase.linno = n->ncase.linno;
280 break;
281 case NCLIST:
282 new->nclist.body = copynode(n->nclist.body);
283 new->nclist.pattern = copynode(n->nclist.pattern);
284 new->nclist.next = copynode(n->nclist.next);
285 break;
286 case NDEFUN:
287 new->ndefun.body = copynode(n->ndefun.body);
288 new->ndefun.text = nodesavestr(n->ndefun.text);
289 new->ndefun.linno = n->ndefun.linno;
290 break;
291 case NARG:
292 new->narg.backquote = copynodelist(n->narg.backquote);
293 new->narg.text = nodesavestr(n->narg.text);
294 new->narg.next = copynode(n->narg.next);
295 break;
296 case NTO:
297 case NCLOBBER:
298 case NFROM:
299 case NFROMTO:
300 case NAPPEND:
301 new->nfile.fname = copynode(n->nfile.fname);
302 new->nfile.fd = n->nfile.fd;
303 new->nfile.next = copynode(n->nfile.next);
304 break;
305 case NTOFD:
306 case NFROMFD:
307 new->ndup.vname = copynode(n->ndup.vname);
308 new->ndup.dupfd = n->ndup.dupfd;
309 new->ndup.fd = n->ndup.fd;
310 new->ndup.next = copynode(n->ndup.next);
311 break;
312 case NHERE:
313 case NXHERE:
314 new->nhere.doc = copynode(n->nhere.doc);
315 new->nhere.fd = n->nhere.fd;
316 new->nhere.next = copynode(n->nhere.next);
317 break;
318 case NNOT:
319 new->nnot.com = copynode(n->nnot.com);
320 break;
321 };
322 new->type = n->type;
323 return new;
324 }
325
326
327 STATIC struct nodelist *
copynodelist(lp)328 copynodelist(lp)
329 struct nodelist *lp;
330 {
331 struct nodelist *start;
332 struct nodelist **lpp;
333
334 lpp = &start;
335 while (lp) {
336 *lpp = funcblock;
337 funcblock = (char *) funcblock +
338 SHELL_ALIGN(sizeof(struct nodelist));
339 (*lpp)->n = copynode(lp->n);
340 lp = lp->next;
341 lpp = &(*lpp)->next;
342 }
343 *lpp = NULL;
344 return start;
345 }
346
347
348
349 STATIC char *
nodesavestr(s)350 nodesavestr(s)
351 char *s;
352 {
353 char *rtn = funcstring;
354
355 funcstring = stpcpy(funcstring, s) + 1;
356 return rtn;
357 }
358
writenode(union node * n,size_t node_size,size_t block_size)359 STATIC void writenode(union node *n, size_t node_size, size_t block_size)
360 {
361 if (block_size > funcblocksize) {
362 sh_error("Unable to encode AST");
363 exraise(-1);
364 }
365 memcpy(funcblock, n, node_size);
366 funcblock = (char *) funcblock + block_size;
367 funcblocksize -= block_size;
368 }
369
370 STATIC void
encodenode(union node * n)371 encodenode(union node *n)
372 {
373 if (n == NULL)
374 return;
375 switch (n->type) {
376 case NCMD:
377 writenode(n, sizeof(struct ncmd), nodesize[n->type]);
378 encodenode(n->ncmd.redirect);
379 encodenode(n->ncmd.args);
380 encodenode(n->ncmd.assign);
381 break;
382 case NPIPE:
383 writenode(n, sizeof(struct npipe), nodesize[n->type]);
384 encodenodelist(n->npipe.cmdlist);
385 break;
386 case NREDIR:
387 case NBACKGND:
388 case NSUBSHELL:
389 writenode(n, sizeof(struct nredir), nodesize[n->type]);
390 encodenode(n->nredir.redirect);
391 encodenode(n->nredir.n);
392 break;
393 case NAND:
394 case NOR:
395 case NSEMI:
396 case NWHILE:
397 case NUNTIL:
398 writenode(n, sizeof(struct nbinary), nodesize[n->type]);
399 encodenode(n->nbinary.ch2);
400 encodenode(n->nbinary.ch1);
401 break;
402 case NIF:
403 writenode(n, sizeof(struct nif), nodesize[n->type]);
404 encodenode(n->nif.elsepart);
405 encodenode(n->nif.ifpart);
406 encodenode(n->nif.test);
407 break;
408 case NFOR:
409 writenode(n, sizeof(struct nfor), nodesize[n->type]);
410 encodestring(n->nfor.var);
411 encodenode(n->nfor.body);
412 encodenode(n->nfor.args);
413 break;
414 case NCASE:
415 writenode(n, sizeof(struct ncase), nodesize[n->type]);
416 encodenode(n->ncase.cases);
417 encodenode(n->ncase.expr);
418 break;
419 case NCLIST:
420 writenode(n, sizeof(struct nclist), nodesize[n->type]);
421 encodenode(n->nclist.body);
422 encodenode(n->nclist.pattern);
423 encodenode(n->nclist.next);
424 break;
425 case NDEFUN:
426 writenode(n, sizeof(struct ndefun), nodesize[n->type]);
427 encodenode(n->ndefun.body);
428 encodestring(n->ndefun.text);
429 break;
430 case NARG:
431 writenode(n, sizeof(struct narg), nodesize[n->type]);
432 encodenodelist(n->narg.backquote);
433 encodestring(n->narg.text);
434 encodenode(n->narg.next);
435 break;
436 case NTO:
437 case NCLOBBER:
438 case NFROM:
439 case NFROMTO:
440 case NAPPEND:
441 writenode(n, sizeof(struct nfile), nodesize[n->type]);
442 encodenode(n->nfile.fname);
443 encodenode(n->nfile.next);
444 break;
445 case NTOFD:
446 case NFROMFD:
447 writenode(n, sizeof(struct ndup), nodesize[n->type]);
448 encodenode(n->ndup.vname);
449 encodenode(n->ndup.next);
450 break;
451 case NHERE:
452 case NXHERE:
453 writenode(n, sizeof(struct nhere), nodesize[n->type]);
454 encodenode(n->nhere.doc);
455 encodenode(n->nhere.next);
456 break;
457 case NNOT:
458 writenode(n, sizeof(struct nnot), nodesize[n->type]);
459 encodenode(n->nnot.com);
460 break;
461 };
462 }
463
464 STATIC void
encodenodelist(struct nodelist * lp)465 encodenodelist(struct nodelist *lp)
466 {
467 while (lp) {
468 memcpy(funcblock, lp, sizeof(struct nodelist));
469 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
470 encodenode(lp->n);
471 lp = lp->next;
472 }
473 }
474
475 STATIC void
encodestring(const char * s)476 encodestring(const char *s)
477 {
478 funcstring = stpcpy(funcstring, s) + 1;
479 }
480
481
482 STATIC void
decodenode(union node ** npp)483 decodenode(union node **npp)
484 {
485 if (*npp == NULL)
486 return;
487 *npp = funcblock;
488 union node *n = *npp;
489 funcblock = (char *) funcblock + nodesize[n->type];
490 switch (n->type) {
491 case NCMD:
492 decodenode(&n->ncmd.redirect);
493 decodenode(&n->ncmd.args);
494 decodenode(&n->ncmd.assign);
495 break;
496 case NPIPE:
497 decodenodelist(&n->npipe.cmdlist);
498 break;
499 case NREDIR:
500 case NBACKGND:
501 case NSUBSHELL:
502 decodenode(&n->nredir.redirect);
503 decodenode(&n->nredir.n);
504 break;
505 case NAND:
506 case NOR:
507 case NSEMI:
508 case NWHILE:
509 case NUNTIL:
510 decodenode(&n->nbinary.ch2);
511 decodenode(&n->nbinary.ch1);
512 break;
513 case NIF:
514 decodenode(&n->nif.elsepart);
515 decodenode(&n->nif.ifpart);
516 decodenode(&n->nif.test);
517 break;
518 case NFOR:
519 n->nfor.var = decodestring();
520 decodenode(&n->nfor.body);
521 decodenode(&n->nfor.args);
522 break;
523 case NCASE:
524 decodenode(&n->ncase.cases);
525 decodenode(&n->ncase.expr);
526 break;
527 case NCLIST:
528 decodenode(&n->nclist.body);
529 decodenode(&n->nclist.pattern);
530 decodenode(&n->nclist.next);
531 break;
532 case NDEFUN:
533 decodenode(&n->ndefun.body);
534 n->ndefun.text = decodestring();
535 break;
536 case NARG:
537 decodenodelist(&n->narg.backquote);
538 n->narg.text = decodestring();
539 decodenode(&n->narg.next);
540 break;
541 case NTO:
542 case NCLOBBER:
543 case NFROM:
544 case NFROMTO:
545 case NAPPEND:
546 decodenode(&n->nfile.fname);
547 decodenode(&n->nfile.next);
548 break;
549 case NTOFD:
550 case NFROMFD:
551 decodenode(&n->ndup.vname);
552 decodenode(&n->ndup.next);
553 break;
554 case NHERE:
555 case NXHERE:
556 decodenode(&n->nhere.doc);
557 decodenode(&n->nhere.next);
558 break;
559 case NNOT:
560 decodenode(&n->nnot.com);
561 break;
562 };
563 }
564
565 STATIC void
decodenodelist(struct nodelist ** lpp)566 decodenodelist(struct nodelist **lpp)
567 {
568 while (*lpp) {
569 *lpp = funcblock;
570 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
571 struct nodelist *lp = *lpp;
572 decodenode(&lp->n);
573 lpp = &lp->next;
574 }
575 }
576
577 STATIC char *
decodestring()578 decodestring()
579 {
580 char *result = funcstring;
581 funcstring += strlen(result) + 1;
582 return result;
583 }
584
585 /*
586 * Free a parse tree.
587 */
588
589 void
freefunc(struct funcnode * f)590 freefunc(struct funcnode *f)
591 {
592 if (f && --f->count < 0)
593 ckfree(f);
594 }
595
596 // Fuchsia-specific:
597 // This is the definition of the header of the VMO used for transferring initialization
598 // information to a subshell. This information would be automatically inherited if we
599 // were able to invoke the subshell using a fork().
600 // For now, we pass symbol table information (non-exported symbols, those are passed in
601 // the environment) and a list of operations to be performed by the subshell.
602 struct state_header
603 {
604 size_t total_size;
605 size_t num_symbols;
606 size_t symtab_offset;
607 size_t cmd_offset;
608 size_t string_offset;
609 };
610 static const size_t kHeaderSize = SHELL_ALIGN(sizeof(struct state_header));
611
612 static char *ignored_syms[] = { "_", "PPID", "PWD" };
613
614 static bool
ignore_sym(char * name)615 ignore_sym(char *name)
616 {
617 for (size_t sym_ndx = 0;
618 sym_ndx < sizeof(ignored_syms) / sizeof(char *);
619 sym_ndx++) {
620 if (!strcmp(ignored_syms[sym_ndx], name)) {
621 return true;
622 }
623 }
624 return false;
625 }
626
627 // Determine the space needed to represent the NULL-terminated symbol table
628 // 'vars'. Also sets 'num_vars' to the number of symbol table entries.
629 static size_t
calc_symtab_size(char ** vars,size_t * num_vars)630 calc_symtab_size(char **vars, size_t *num_vars)
631 {
632 size_t total_len = 0;
633 *num_vars = 0;
634 while (*vars) {
635 if (! ignore_sym(*vars)) {
636 // + 2 for NULL symbol flags
637 total_len += strlen(*vars) + 2;
638 (*num_vars)++;
639 }
640 vars++;
641 }
642 return total_len;
643 }
644
645 // Write symbols into 'buffer'. If 'is_readonly' is set, all variables are
646 // marked as such.
647 static size_t
output_symtab(char * buffer,char ** vars,bool is_readonly)648 output_symtab(char *buffer, char **vars, bool is_readonly)
649 {
650 char *orig_buffer = buffer;
651 while (*vars) {
652 if (! ignore_sym(*vars)) {
653 *buffer++ = is_readonly ? 1 : 0;
654 size_t len = strlen(*vars);
655 buffer = mempcpy(buffer, *vars, len + 1);
656 }
657 vars++;
658 }
659 return buffer - orig_buffer;
660 }
661
662 // Read in symbols from the encoded table 'buffer'. We currently only support
663 // two variants of variables: readonly (flags == 1) and writable (flags == 0).
664 static void
restore_symtab(char * buffer,size_t num_syms)665 restore_symtab(char *buffer, size_t num_syms)
666 {
667 while(num_syms--) {
668 bool is_readonly = (*buffer++ == 1);
669 setvareq(buffer, is_readonly ? VREADONLY : 0);
670 buffer += (strlen(buffer) + 1);
671 }
672 }
673
674 // The encoded format contains four segments:
675 //
676 // * A header that specifies the number of symbols, and offsets of each of
677 // the three segments (see "struct state_header").
678 // * A symbol table. Each entry in the symbol table is a single-byte of flags
679 // (1 = read-only, 0 = writable) followed by a NULL-terminted NAME=VALUE
680 // string.
681 // * A sequence of nodes in a pre-order traversal of the node tree.
682 // - The encoded size of each node is determined by its type.
683 // - Pointer fields in each node contain zero if that pointer should decode
684 // a NULL. Otherwise, if the pointer should decode as non-NULL, the field
685 // contains an arbitrary non-zero value. (These values are the address of
686 // the node or the string in the encoding process, which isn't meaningful to
687 // the decoding progress).
688 // * A sequence of null-terminated strings, in the order the strings are
689 // encountered in a pre-order traversal of the node tree.
690
691 zx_status_t
codec_encode(struct nodelist * nlist,zx_handle_t * vmo)692 codec_encode(struct nodelist *nlist, zx_handle_t *vmo)
693 {
694 funcblocksize = 0;
695 funcstringsize = 0;
696 char **writable_vars = listvars(0, VEXPORT | VREADONLY, 0);
697 char **readonly_vars = listvars(VREADONLY, VEXPORT, 0);
698
699 // Calculate the size of the components
700 size_t num_writable_vars;
701 size_t num_readonly_vars;
702 size_t total_symtab_size = calc_symtab_size(writable_vars, &num_writable_vars) +
703 calc_symtab_size(readonly_vars, &num_readonly_vars);
704 total_symtab_size = SHELL_ALIGN(total_symtab_size);
705 sizenodelist(nlist);
706 struct state_header header;
707
708 // Fill in the header
709 header.num_symbols = num_writable_vars + num_readonly_vars;
710 header.symtab_offset = kHeaderSize;
711 header.cmd_offset = header.symtab_offset + total_symtab_size;
712 header.string_offset = header.cmd_offset + funcblocksize;
713
714 char buffer[header.string_offset + funcstringsize];
715 header.total_size = sizeof(buffer);
716
717 // Output the symbol tables
718 memcpy(buffer, &header, sizeof(header));
719 size_t symtab_offset = header.symtab_offset;
720 char* symtab = &buffer[symtab_offset];
721 symtab_offset += output_symtab(symtab, writable_vars, 0);
722 output_symtab(symtab, readonly_vars, 1);
723
724 // Output the command nodes
725 funcblock = buffer + header.cmd_offset;
726 funcstring = buffer + header.string_offset;
727 encodenodelist(nlist);
728
729 // And VMO-ify the whole thing
730 zx_status_t status = zx_vmo_create(sizeof(buffer), 0, vmo);
731 if (status != ZX_OK)
732 return status;
733 return zx_vmo_write(*vmo, buffer, 0, sizeof(buffer));
734 }
735
codec_decode(char * buffer,size_t length)736 struct nodelist *codec_decode(char *buffer, size_t length)
737 {
738 struct state_header header;
739 if (length < sizeof(header)) {
740 return NULL;
741 }
742 memcpy(&header, buffer, sizeof(header));
743 if (length < header.total_size) {
744 return NULL;
745 }
746
747 restore_symtab(buffer + header.symtab_offset, header.num_symbols);
748 funcblock = buffer + header.cmd_offset;
749 funcstring = buffer + header.string_offset;
750 struct nodelist dummy;
751 // The decodenodelist API is very... unique. It needs the
752 // argument to point to something non-NULL, even though the
753 // argument is otherwise ignored and used as an output parameter.
754 struct nodelist *nlist = &dummy;
755 decodenodelist(&nlist);
756 return nlist;
757 }
758
759