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
58int     funcblocksize;		/* size of structures in function */
59int     funcstringsize;		/* size of strings in node */
60pointer funcblock;		/* block to allocate function from */
61char   *funcstring;		/* block to allocate strings from */
62
63static 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
93STATIC void calcsize(union node *);
94STATIC void sizenodelist(struct nodelist *);
95STATIC union node *copynode(union node *);
96STATIC struct nodelist *copynodelist(struct nodelist *);
97STATIC char *nodesavestr(char *);
98
99STATIC void writenode(union node *n, size_t node_size, size_t block_size);
100STATIC void encodenode(union node *);
101STATIC void encodenodelist(struct nodelist *);
102STATIC void encodestring(const char *);
103
104STATIC void decodenode(union node **);
105STATIC void decodenodelist(struct nodelist **);
106STATIC char *decodestring();
107
108/*
109 * Make a copy of a parse tree.
110 */
111
112struct funcnode *
113copyfunc(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
132STATIC void
133calcsize(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
216STATIC void
217sizenodelist(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
229STATIC union node *
230copynode(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
327STATIC struct nodelist *
328copynodelist(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
349STATIC char *
350nodesavestr(s)
351	char   *s;
352{
353	char   *rtn = funcstring;
354
355	funcstring = stpcpy(funcstring, s) + 1;
356	return rtn;
357}
358
359STATIC 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
370STATIC void
371encodenode(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
464STATIC void
465encodenodelist(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
475STATIC void
476encodestring(const char *s)
477{
478	funcstring = stpcpy(funcstring, s) + 1;
479}
480
481
482STATIC void
483decodenode(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
565STATIC void
566decodenodelist(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
577STATIC char *
578decodestring()
579{
580	char *result = funcstring;
581	funcstring += strlen(result) + 1;
582	return result;
583}
584
585/*
586 * Free a parse tree.
587 */
588
589void
590freefunc(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.
602struct 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};
610static const size_t kHeaderSize = SHELL_ALIGN(sizeof(struct state_header));
611
612static char *ignored_syms[] = { "_", "PPID", "PWD" };
613
614static bool
615ignore_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.
629static size_t
630calc_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.
647static size_t
648output_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).
664static void
665restore_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
691zx_status_t
692codec_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
736struct 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