1ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin/*
2ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
3ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * All rights reserved.
4ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin *
5ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * Redistribution and use in source and binary forms, with or without
6ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * modification, are permitted provided that the following conditions
7ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * are met:
8ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * 1. Redistributions of source code must retain the above copyright
9ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin *    notice, this list of conditions and the following disclaimer.
10ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * 2. Redistributions in binary form must reproduce the above copyright
11ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin *    notice, this list of conditions and the following disclaimer in the
12ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin *    documentation and/or other materials provided with the distribution.
13ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * 3. The name of the author may not be used to endorse or promote products
14ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin *    derived from this software without specific prior written permission.
15ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin *
16ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin */
27ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
28ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#include "defs.h"
29ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
30ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#ifdef HAVE_LINUX_BPF_H
31ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin# include <linux/bpf.h>
32ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#endif
33ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
34ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#include "xlat/bpf_commands.h"
35ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#include "xlat/bpf_map_types.h"
36ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#include "xlat/bpf_prog_types.h"
37ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin#include "xlat/bpf_map_update_elem_flags.h"
38ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
39ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinstatic int
40ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinbpf_map_create(struct tcb *tcp, const long addr, unsigned int size)
41ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin{
42ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	struct {
43ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t map_type, key_size, value_size, max_entries;
44ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	} attr = {};
45ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
46ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (!size) {
47ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printaddr(addr);
48ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED | RVAL_FD;
49ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
50ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (size > sizeof(attr))
51ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		size = sizeof(attr);
52ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (umoven_or_printaddr(tcp, addr, size, &attr))
53ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED | RVAL_FD;
54ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
55ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprints("{map_type=");
56ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printxval(bpf_map_types, attr.map_type, "BPF_MAP_TYPE_???");
57ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprintf(", key_size=%u, value_size=%u, max_entries=%u}",
58ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		attr.key_size, attr.value_size, attr.max_entries);
59ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
60ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	return RVAL_DECODED | RVAL_FD;
61ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin}
62ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
63ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinstatic void
64ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinbpf_map_update_elem(struct tcb *tcp, const long addr, unsigned int size)
65ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin{
66ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	struct {
67ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t map_fd;
68ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) key;
69ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) value;
70ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t flags;
71ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	} attr = {};
72ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
73ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (!size) {
74ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printaddr(addr);
75ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return;
76ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
77ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (size > sizeof(attr))
78ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		size = sizeof(attr);
79ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (umoven_or_printaddr(tcp, addr, size, &attr))
80ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return;
81ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
82ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprints("{map_fd=");
83ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printfd(tcp, attr.map_fd);
84ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprintf(", key=%#" PRIx64 ", value=%#" PRIx64 ", flags=",
85ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		attr.key, attr.value);
86ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printxval(bpf_map_update_elem_flags, attr.flags, "BPF_???");
87ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprints("}");
88ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin}
89ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
90ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinstatic void
91ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinbpf_map_delete_elem(struct tcb *tcp, const long addr, unsigned int size)
92ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin{
93ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	struct {
94ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t map_fd;
95ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) key;
96ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	} attr = {};
97ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
98ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (!size) {
99ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printaddr(addr);
100ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return;
101ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
102ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (size > sizeof(attr))
103ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		size = sizeof(attr);
104ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (umoven_or_printaddr(tcp, addr, size, &attr))
105ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return;
106ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
107ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprints("{map_fd=");
108ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printfd(tcp, attr.map_fd);
109ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprintf(", key=%#" PRIx64 "}", attr.key);
110ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin}
111ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
112ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinstatic int
113ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinbpf_map_io(struct tcb *tcp, const long addr, unsigned int size, const char *text)
114ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin{
115ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	struct bpf_io_elem_struct {
116ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t map_fd;
117ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) key;
118ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) value;
119ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	} attr = {};
120ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
121ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (exiting(tcp)) {
122ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		if (!syserror(tcp) && !umove_or_printaddr(tcp, addr, &attr))
123ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin			tprintf(", %s=%#" PRIx64, text, attr.value);
124ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		tprints("}");
125ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED;
126ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
127ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
128ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (!size) {
129ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printaddr(addr);
130ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED;
131ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
132ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (size > sizeof(attr))
133ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		size = sizeof(attr);
134ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (umoven_or_printaddr(tcp, addr, size, &attr))
135ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED;
136ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
137ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprints("{map_fd=");
138ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printfd(tcp, attr.map_fd);
139ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprintf(", key=%#" PRIx64, attr.key);
140ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
141ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	return 0;
142ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin}
143ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
144ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinstatic int
145ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levinbpf_prog_load(struct tcb *tcp, const long addr, unsigned int size)
146ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin{
147ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	struct {
148ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t prog_type, insn_cnt;
149ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) insns, license;
150ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t log_level, log_size;
151ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint64_t ATTRIBUTE_ALIGNED(8) log_buf;
152ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		uint32_t kern_version;
153ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	} attr = {};
154ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
155ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (!size) {
156ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printaddr(addr);
157ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED | RVAL_FD;
158ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
159ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (size > sizeof(attr))
160ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		size = sizeof(attr);
161ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (umoven_or_printaddr(tcp, addr, size, &attr))
162ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		return RVAL_DECODED | RVAL_FD;
163ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
164ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprints("{prog_type=");
165ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printxval(bpf_prog_types, attr.prog_type, "BPF_PROG_TYPE_???");
166ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprintf(", insn_cnt=%u, insns=%#" PRIx64 ", license=",
167ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		attr.insn_cnt, attr.insns);
168ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	printstr(tcp, attr.license, -1);
169ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	tprintf(", log_level=%u, log_size=%u, log_buf=%#" PRIx64 ", kern_version=%u}",
170ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		attr.log_level, attr.log_size, attr.log_buf, attr.kern_version);
171ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
172ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	return RVAL_DECODED | RVAL_FD;
173ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin}
174ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
175ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. LevinSYS_FUNC(bpf)
176ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin{
177ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	const int cmd = tcp->u_arg[0];
178ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	const long addr = tcp->u_arg[1];
179ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	const unsigned int size = tcp->u_arg[2];
180ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	int rc = RVAL_DECODED;
181ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
182ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (entering(tcp)) {
183ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printxval(bpf_commands, cmd, "BPF_???");
184ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		tprints(", ");
185ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
186ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
187ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	switch (cmd) {
188ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	case BPF_MAP_CREATE:
189ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		rc = bpf_map_create(tcp, addr, size);
190ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
191ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	case BPF_MAP_LOOKUP_ELEM:
192ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		rc = bpf_map_io(tcp, addr, size, "value");
193ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
194ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	case BPF_MAP_UPDATE_ELEM:
195ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		bpf_map_update_elem(tcp, addr, size);
196ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
197ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	case BPF_MAP_DELETE_ELEM:
198ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		bpf_map_delete_elem(tcp, addr, size);
199ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
200ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	case BPF_MAP_GET_NEXT_KEY:
201ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		rc = bpf_map_io(tcp, addr, size, "next_key");
202ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
203ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	case BPF_PROG_LOAD:
204ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		rc = bpf_prog_load(tcp, addr, size);
205ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
206ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	default:
207ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		printaddr(addr);
208ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		break;
209ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	}
210ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
211ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	if (rc & RVAL_DECODED)
212ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin		tprintf(", %u", size);
213ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin
214ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin	return rc;
215ddb53dd142ea6702afbc1ff238840969183a709dDmitry V. Levin}
216