/src/libbpf/src/btf_relocate.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
2 | | /* Copyright (c) 2024, Oracle and/or its affiliates. */ |
3 | | |
4 | | #ifndef _GNU_SOURCE |
5 | | #define _GNU_SOURCE |
6 | | #endif |
7 | | |
8 | | #ifdef __KERNEL__ |
9 | | #include <linux/bpf.h> |
10 | | #include <linux/bsearch.h> |
11 | | #include <linux/btf.h> |
12 | | #include <linux/sort.h> |
13 | | #include <linux/string.h> |
14 | | #include <linux/bpf_verifier.h> |
15 | | |
16 | | #define btf_type_by_id (struct btf_type *)btf_type_by_id |
17 | | #define btf__type_cnt btf_nr_types |
18 | | #define btf__base_btf btf_base_btf |
19 | | #define btf__name_by_offset btf_name_by_offset |
20 | | #define btf__str_by_offset btf_str_by_offset |
21 | | #define btf_kflag btf_type_kflag |
22 | | |
23 | | #define calloc(nmemb, sz) kvcalloc(nmemb, sz, GFP_KERNEL | __GFP_NOWARN) |
24 | | #define free(ptr) kvfree(ptr) |
25 | | #define qsort(base, num, sz, cmp) sort(base, num, sz, cmp, NULL) |
26 | | |
27 | | #else |
28 | | |
29 | | #include "btf.h" |
30 | | #include "bpf.h" |
31 | | #include "libbpf.h" |
32 | | #include "libbpf_internal.h" |
33 | | |
34 | | #endif /* __KERNEL__ */ |
35 | | |
36 | | struct btf; |
37 | | |
38 | | struct btf_relocate { |
39 | | struct btf *btf; |
40 | | const struct btf *base_btf; |
41 | | const struct btf *dist_base_btf; |
42 | | unsigned int nr_base_types; |
43 | | unsigned int nr_split_types; |
44 | | unsigned int nr_dist_base_types; |
45 | | int dist_str_len; |
46 | | int base_str_len; |
47 | | __u32 *id_map; |
48 | | __u32 *str_map; |
49 | | }; |
50 | | |
51 | | /* Set temporarily in relocation id_map if distilled base struct/union is |
52 | | * embedded in a split BTF struct/union; in such a case, size information must |
53 | | * match between distilled base BTF and base BTF representation of type. |
54 | | */ |
55 | 0 | #define BTF_IS_EMBEDDED ((__u32)-1) |
56 | | |
57 | | /* <name, size, id> triple used in sorting/searching distilled base BTF. */ |
58 | | struct btf_name_info { |
59 | | const char *name; |
60 | | /* set when search requires a size match */ |
61 | | bool needs_size: 1; |
62 | | unsigned int size: 31; |
63 | | __u32 id; |
64 | | }; |
65 | | |
66 | | static int btf_relocate_rewrite_type_id(struct btf_relocate *r, __u32 i) |
67 | 0 | { |
68 | 0 | struct btf_type *t = btf_type_by_id(r->btf, i); |
69 | 0 | struct btf_field_iter it; |
70 | 0 | __u32 *id; |
71 | 0 | int err; |
72 | |
|
73 | 0 | err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); |
74 | 0 | if (err) |
75 | 0 | return err; |
76 | | |
77 | 0 | while ((id = btf_field_iter_next(&it))) |
78 | 0 | *id = r->id_map[*id]; |
79 | 0 | return 0; |
80 | 0 | } |
81 | | |
82 | | /* Simple string comparison used for sorting within BTF, since all distilled |
83 | | * types are named. If strings match, and size is non-zero for both elements |
84 | | * fall back to using size for ordering. |
85 | | */ |
86 | | static int cmp_btf_name_size(const void *n1, const void *n2) |
87 | 0 | { |
88 | 0 | const struct btf_name_info *ni1 = n1; |
89 | 0 | const struct btf_name_info *ni2 = n2; |
90 | 0 | int name_diff = strcmp(ni1->name, ni2->name); |
91 | |
|
92 | 0 | if (!name_diff && ni1->needs_size && ni2->needs_size) |
93 | 0 | return ni2->size - ni1->size; |
94 | 0 | return name_diff; |
95 | 0 | } |
96 | | |
97 | | /* Binary search with a small twist; find leftmost element that matches |
98 | | * so that we can then iterate through all exact matches. So for example |
99 | | * searching { "a", "bb", "bb", "c" } we would always match on the |
100 | | * leftmost "bb". |
101 | | */ |
102 | | static struct btf_name_info *search_btf_name_size(struct btf_name_info *key, |
103 | | struct btf_name_info *vals, |
104 | | int nelems) |
105 | 0 | { |
106 | 0 | struct btf_name_info *ret = NULL; |
107 | 0 | int high = nelems - 1; |
108 | 0 | int low = 0; |
109 | |
|
110 | 0 | while (low <= high) { |
111 | 0 | int mid = (low + high)/2; |
112 | 0 | struct btf_name_info *val = &vals[mid]; |
113 | 0 | int diff = cmp_btf_name_size(key, val); |
114 | |
|
115 | 0 | if (diff == 0) |
116 | 0 | ret = val; |
117 | | /* even if found, keep searching for leftmost match */ |
118 | 0 | if (diff <= 0) |
119 | 0 | high = mid - 1; |
120 | 0 | else |
121 | 0 | low = mid + 1; |
122 | 0 | } |
123 | 0 | return ret; |
124 | 0 | } |
125 | | |
126 | | /* If a member of a split BTF struct/union refers to a base BTF |
127 | | * struct/union, mark that struct/union id temporarily in the id_map |
128 | | * with BTF_IS_EMBEDDED. Members can be const/restrict/volatile/typedef |
129 | | * reference types, but if a pointer is encountered, the type is no longer |
130 | | * considered embedded. |
131 | | */ |
132 | | static int btf_mark_embedded_composite_type_ids(struct btf_relocate *r, __u32 i) |
133 | 0 | { |
134 | 0 | struct btf_type *t = btf_type_by_id(r->btf, i); |
135 | 0 | struct btf_field_iter it; |
136 | 0 | __u32 *id; |
137 | 0 | int err; |
138 | |
|
139 | 0 | if (!btf_is_composite(t)) |
140 | 0 | return 0; |
141 | | |
142 | 0 | err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); |
143 | 0 | if (err) |
144 | 0 | return err; |
145 | | |
146 | 0 | while ((id = btf_field_iter_next(&it))) { |
147 | 0 | __u32 next_id = *id; |
148 | |
|
149 | 0 | while (next_id) { |
150 | 0 | t = btf_type_by_id(r->btf, next_id); |
151 | 0 | switch (btf_kind(t)) { |
152 | 0 | case BTF_KIND_CONST: |
153 | 0 | case BTF_KIND_RESTRICT: |
154 | 0 | case BTF_KIND_VOLATILE: |
155 | 0 | case BTF_KIND_TYPEDEF: |
156 | 0 | case BTF_KIND_TYPE_TAG: |
157 | 0 | next_id = t->type; |
158 | 0 | break; |
159 | 0 | case BTF_KIND_ARRAY: { |
160 | 0 | struct btf_array *a = btf_array(t); |
161 | |
|
162 | 0 | next_id = a->type; |
163 | 0 | break; |
164 | 0 | } |
165 | 0 | case BTF_KIND_STRUCT: |
166 | 0 | case BTF_KIND_UNION: |
167 | 0 | if (next_id < r->nr_dist_base_types) |
168 | 0 | r->id_map[next_id] = BTF_IS_EMBEDDED; |
169 | 0 | next_id = 0; |
170 | 0 | break; |
171 | 0 | default: |
172 | 0 | next_id = 0; |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | 0 | return 0; |
179 | 0 | } |
180 | | |
181 | | /* Build a map from distilled base BTF ids to base BTF ids. To do so, iterate |
182 | | * through base BTF looking up distilled type (using binary search) equivalents. |
183 | | */ |
184 | | static int btf_relocate_map_distilled_base(struct btf_relocate *r) |
185 | 0 | { |
186 | 0 | struct btf_name_info *info, *info_end; |
187 | 0 | struct btf_type *base_t, *dist_t; |
188 | 0 | __u8 *base_name_cnt = NULL; |
189 | 0 | int err = 0; |
190 | 0 | __u32 id; |
191 | | |
192 | | /* generate a sort index array of name/type ids sorted by name for |
193 | | * distilled base BTF to speed name-based lookups. |
194 | | */ |
195 | 0 | info = calloc(r->nr_dist_base_types, sizeof(*info)); |
196 | 0 | if (!info) { |
197 | 0 | err = -ENOMEM; |
198 | 0 | goto done; |
199 | 0 | } |
200 | 0 | info_end = info + r->nr_dist_base_types; |
201 | 0 | for (id = 0; id < r->nr_dist_base_types; id++) { |
202 | 0 | dist_t = btf_type_by_id(r->dist_base_btf, id); |
203 | 0 | info[id].name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off); |
204 | 0 | info[id].id = id; |
205 | 0 | info[id].size = dist_t->size; |
206 | 0 | info[id].needs_size = true; |
207 | 0 | } |
208 | 0 | qsort(info, r->nr_dist_base_types, sizeof(*info), cmp_btf_name_size); |
209 | | |
210 | | /* Mark distilled base struct/union members of split BTF structs/unions |
211 | | * in id_map with BTF_IS_EMBEDDED; this signals that these types |
212 | | * need to match both name and size, otherwise embedding the base |
213 | | * struct/union in the split type is invalid. |
214 | | */ |
215 | 0 | for (id = r->nr_dist_base_types; id < r->nr_dist_base_types + r->nr_split_types; id++) { |
216 | 0 | err = btf_mark_embedded_composite_type_ids(r, id); |
217 | 0 | if (err) |
218 | 0 | goto done; |
219 | 0 | } |
220 | | |
221 | | /* Collect name counts for composite types in base BTF. If multiple |
222 | | * instances of a struct/union of the same name exist, we need to use |
223 | | * size to determine which to map to since name alone is ambiguous. |
224 | | */ |
225 | 0 | base_name_cnt = calloc(r->base_str_len, sizeof(*base_name_cnt)); |
226 | 0 | if (!base_name_cnt) { |
227 | 0 | err = -ENOMEM; |
228 | 0 | goto done; |
229 | 0 | } |
230 | 0 | for (id = 1; id < r->nr_base_types; id++) { |
231 | 0 | base_t = btf_type_by_id(r->base_btf, id); |
232 | 0 | if (!btf_is_composite(base_t) || !base_t->name_off) |
233 | 0 | continue; |
234 | 0 | if (base_name_cnt[base_t->name_off] < 255) |
235 | 0 | base_name_cnt[base_t->name_off]++; |
236 | 0 | } |
237 | | |
238 | | /* Now search base BTF for matching distilled base BTF types. */ |
239 | 0 | for (id = 1; id < r->nr_base_types; id++) { |
240 | 0 | struct btf_name_info *dist_info, base_info = {}; |
241 | 0 | int dist_kind, base_kind; |
242 | |
|
243 | 0 | base_t = btf_type_by_id(r->base_btf, id); |
244 | | /* distilled base consists of named types only. */ |
245 | 0 | if (!base_t->name_off) |
246 | 0 | continue; |
247 | 0 | base_kind = btf_kind(base_t); |
248 | 0 | base_info.id = id; |
249 | 0 | base_info.name = btf__name_by_offset(r->base_btf, base_t->name_off); |
250 | 0 | switch (base_kind) { |
251 | 0 | case BTF_KIND_INT: |
252 | 0 | case BTF_KIND_FLOAT: |
253 | 0 | case BTF_KIND_ENUM: |
254 | 0 | case BTF_KIND_ENUM64: |
255 | | /* These types should match both name and size */ |
256 | 0 | base_info.needs_size = true; |
257 | 0 | base_info.size = base_t->size; |
258 | 0 | break; |
259 | 0 | case BTF_KIND_FWD: |
260 | | /* No size considerations for fwds. */ |
261 | 0 | break; |
262 | 0 | case BTF_KIND_STRUCT: |
263 | 0 | case BTF_KIND_UNION: |
264 | | /* Size only needs to be used for struct/union if there |
265 | | * are multiple types in base BTF with the same name. |
266 | | * If there are multiple _distilled_ types with the same |
267 | | * name (a very unlikely scenario), that doesn't matter |
268 | | * unless corresponding _base_ types to match them are |
269 | | * missing. |
270 | | */ |
271 | 0 | base_info.needs_size = base_name_cnt[base_t->name_off] > 1; |
272 | 0 | base_info.size = base_t->size; |
273 | 0 | break; |
274 | 0 | default: |
275 | 0 | continue; |
276 | 0 | } |
277 | | /* iterate over all matching distilled base types */ |
278 | 0 | for (dist_info = search_btf_name_size(&base_info, info, r->nr_dist_base_types); |
279 | 0 | dist_info != NULL && dist_info < info_end && |
280 | 0 | cmp_btf_name_size(&base_info, dist_info) == 0; |
281 | 0 | dist_info++) { |
282 | 0 | if (!dist_info->id || dist_info->id >= r->nr_dist_base_types) { |
283 | 0 | pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n", |
284 | 0 | id, dist_info->id); |
285 | 0 | err = -EINVAL; |
286 | 0 | goto done; |
287 | 0 | } |
288 | 0 | dist_t = btf_type_by_id(r->dist_base_btf, dist_info->id); |
289 | 0 | dist_kind = btf_kind(dist_t); |
290 | | |
291 | | /* Validate that the found distilled type is compatible. |
292 | | * Do not error out on mismatch as another match may |
293 | | * occur for an identically-named type. |
294 | | */ |
295 | 0 | switch (dist_kind) { |
296 | 0 | case BTF_KIND_FWD: |
297 | 0 | switch (base_kind) { |
298 | 0 | case BTF_KIND_FWD: |
299 | 0 | if (btf_kflag(dist_t) != btf_kflag(base_t)) |
300 | 0 | continue; |
301 | 0 | break; |
302 | 0 | case BTF_KIND_STRUCT: |
303 | 0 | if (btf_kflag(base_t)) |
304 | 0 | continue; |
305 | 0 | break; |
306 | 0 | case BTF_KIND_UNION: |
307 | 0 | if (!btf_kflag(base_t)) |
308 | 0 | continue; |
309 | 0 | break; |
310 | 0 | default: |
311 | 0 | continue; |
312 | 0 | } |
313 | 0 | break; |
314 | 0 | case BTF_KIND_INT: |
315 | 0 | if (dist_kind != base_kind || |
316 | 0 | btf_int_encoding(base_t) != btf_int_encoding(dist_t)) |
317 | 0 | continue; |
318 | 0 | break; |
319 | 0 | case BTF_KIND_FLOAT: |
320 | 0 | if (dist_kind != base_kind) |
321 | 0 | continue; |
322 | 0 | break; |
323 | 0 | case BTF_KIND_ENUM: |
324 | | /* ENUM and ENUM64 are encoded as sized ENUM in |
325 | | * distilled base BTF. |
326 | | */ |
327 | 0 | if (base_kind != dist_kind && base_kind != BTF_KIND_ENUM64) |
328 | 0 | continue; |
329 | 0 | break; |
330 | 0 | case BTF_KIND_STRUCT: |
331 | 0 | case BTF_KIND_UNION: |
332 | | /* size verification is required for embedded |
333 | | * struct/unions. |
334 | | */ |
335 | 0 | if (r->id_map[dist_info->id] == BTF_IS_EMBEDDED && |
336 | 0 | base_t->size != dist_t->size) |
337 | 0 | continue; |
338 | 0 | break; |
339 | 0 | default: |
340 | 0 | continue; |
341 | 0 | } |
342 | 0 | if (r->id_map[dist_info->id] && |
343 | 0 | r->id_map[dist_info->id] != BTF_IS_EMBEDDED) { |
344 | | /* we already have a match; this tells us that |
345 | | * multiple base types of the same name |
346 | | * have the same size, since for cases where |
347 | | * multiple types have the same name we match |
348 | | * on name and size. In this case, we have |
349 | | * no way of determining which to relocate |
350 | | * to in base BTF, so error out. |
351 | | */ |
352 | 0 | pr_warn("distilled base BTF type '%s' [%u], size %u has multiple candidates of the same size (ids [%u, %u]) in base BTF\n", |
353 | 0 | base_info.name, dist_info->id, |
354 | 0 | base_t->size, id, r->id_map[dist_info->id]); |
355 | 0 | err = -EINVAL; |
356 | 0 | goto done; |
357 | 0 | } |
358 | | /* map id and name */ |
359 | 0 | r->id_map[dist_info->id] = id; |
360 | 0 | r->str_map[dist_t->name_off] = base_t->name_off; |
361 | 0 | } |
362 | 0 | } |
363 | | /* ensure all distilled BTF ids now have a mapping... */ |
364 | 0 | for (id = 1; id < r->nr_dist_base_types; id++) { |
365 | 0 | const char *name; |
366 | |
|
367 | 0 | if (r->id_map[id] && r->id_map[id] != BTF_IS_EMBEDDED) |
368 | 0 | continue; |
369 | 0 | dist_t = btf_type_by_id(r->dist_base_btf, id); |
370 | 0 | name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off); |
371 | 0 | pr_warn("distilled base BTF type '%s' [%d] is not mapped to base BTF id\n", |
372 | 0 | name, id); |
373 | 0 | err = -EINVAL; |
374 | 0 | break; |
375 | 0 | } |
376 | 0 | done: |
377 | 0 | free(base_name_cnt); |
378 | 0 | free(info); |
379 | 0 | return err; |
380 | 0 | } |
381 | | |
382 | | /* distilled base should only have named int/float/enum/fwd/struct/union types. */ |
383 | | static int btf_relocate_validate_distilled_base(struct btf_relocate *r) |
384 | 0 | { |
385 | 0 | unsigned int i; |
386 | |
|
387 | 0 | for (i = 1; i < r->nr_dist_base_types; i++) { |
388 | 0 | struct btf_type *t = btf_type_by_id(r->dist_base_btf, i); |
389 | 0 | int kind = btf_kind(t); |
390 | |
|
391 | 0 | switch (kind) { |
392 | 0 | case BTF_KIND_INT: |
393 | 0 | case BTF_KIND_FLOAT: |
394 | 0 | case BTF_KIND_ENUM: |
395 | 0 | case BTF_KIND_STRUCT: |
396 | 0 | case BTF_KIND_UNION: |
397 | 0 | case BTF_KIND_FWD: |
398 | 0 | if (t->name_off) |
399 | 0 | break; |
400 | 0 | pr_warn("type [%d], kind [%d] is invalid for distilled base BTF; it is anonymous\n", |
401 | 0 | i, kind); |
402 | 0 | return -EINVAL; |
403 | 0 | default: |
404 | 0 | pr_warn("type [%d] in distilled based BTF has unexpected kind [%d]\n", |
405 | 0 | i, kind); |
406 | 0 | return -EINVAL; |
407 | 0 | } |
408 | 0 | } |
409 | 0 | return 0; |
410 | 0 | } |
411 | | |
412 | | static int btf_relocate_rewrite_strs(struct btf_relocate *r, __u32 i) |
413 | 0 | { |
414 | 0 | struct btf_type *t = btf_type_by_id(r->btf, i); |
415 | 0 | struct btf_field_iter it; |
416 | 0 | __u32 *str_off; |
417 | 0 | int off, err; |
418 | |
|
419 | 0 | err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_STRS); |
420 | 0 | if (err) |
421 | 0 | return err; |
422 | | |
423 | 0 | while ((str_off = btf_field_iter_next(&it))) { |
424 | 0 | if (!*str_off) |
425 | 0 | continue; |
426 | 0 | if (*str_off >= r->dist_str_len) { |
427 | 0 | *str_off += r->base_str_len - r->dist_str_len; |
428 | 0 | } else { |
429 | 0 | off = r->str_map[*str_off]; |
430 | 0 | if (!off) { |
431 | 0 | pr_warn("string '%s' [offset %u] is not mapped to base BTF\n", |
432 | 0 | btf__str_by_offset(r->btf, off), *str_off); |
433 | 0 | return -ENOENT; |
434 | 0 | } |
435 | 0 | *str_off = off; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | return 0; |
439 | 0 | } |
440 | | |
441 | | /* If successful, output of relocation is updated BTF with base BTF pointing |
442 | | * at base_btf, and type ids, strings adjusted accordingly. |
443 | | */ |
444 | | int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map) |
445 | 0 | { |
446 | 0 | unsigned int nr_types = btf__type_cnt(btf); |
447 | 0 | const struct btf_header *dist_base_hdr; |
448 | 0 | const struct btf_header *base_hdr; |
449 | 0 | struct btf_relocate r = {}; |
450 | 0 | int err = 0; |
451 | 0 | __u32 id, i; |
452 | |
|
453 | 0 | r.dist_base_btf = btf__base_btf(btf); |
454 | 0 | if (!base_btf || r.dist_base_btf == base_btf) |
455 | 0 | return -EINVAL; |
456 | | |
457 | 0 | r.nr_dist_base_types = btf__type_cnt(r.dist_base_btf); |
458 | 0 | r.nr_base_types = btf__type_cnt(base_btf); |
459 | 0 | r.nr_split_types = nr_types - r.nr_dist_base_types; |
460 | 0 | r.btf = btf; |
461 | 0 | r.base_btf = base_btf; |
462 | |
|
463 | 0 | r.id_map = calloc(nr_types, sizeof(*r.id_map)); |
464 | 0 | r.str_map = calloc(btf_header(r.dist_base_btf)->str_len, sizeof(*r.str_map)); |
465 | 0 | dist_base_hdr = btf_header(r.dist_base_btf); |
466 | 0 | base_hdr = btf_header(r.base_btf); |
467 | 0 | r.dist_str_len = dist_base_hdr->str_len; |
468 | 0 | r.base_str_len = base_hdr->str_len; |
469 | 0 | if (!r.id_map || !r.str_map) { |
470 | 0 | err = -ENOMEM; |
471 | 0 | goto err_out; |
472 | 0 | } |
473 | | |
474 | 0 | err = btf_relocate_validate_distilled_base(&r); |
475 | 0 | if (err) |
476 | 0 | goto err_out; |
477 | | |
478 | | /* Split BTF ids need to be adjusted as base and distilled base |
479 | | * have different numbers of types, changing the start id of split |
480 | | * BTF. |
481 | | */ |
482 | 0 | for (id = r.nr_dist_base_types; id < nr_types; id++) |
483 | 0 | r.id_map[id] = id + r.nr_base_types - r.nr_dist_base_types; |
484 | | |
485 | | /* Build a map from distilled base ids to actual base BTF ids; it is used |
486 | | * to update split BTF id references. Also build a str_map mapping from |
487 | | * distilled base BTF names to base BTF names. |
488 | | */ |
489 | 0 | err = btf_relocate_map_distilled_base(&r); |
490 | 0 | if (err) |
491 | 0 | goto err_out; |
492 | | |
493 | | /* Next, rewrite type ids in split BTF, replacing split ids with updated |
494 | | * ids based on number of types in base BTF, and base ids with |
495 | | * relocated ids from base_btf. |
496 | | */ |
497 | 0 | for (i = 0, id = r.nr_dist_base_types; i < r.nr_split_types; i++, id++) { |
498 | 0 | err = btf_relocate_rewrite_type_id(&r, id); |
499 | 0 | if (err) |
500 | 0 | goto err_out; |
501 | 0 | } |
502 | | /* String offsets now need to be updated using the str_map. */ |
503 | 0 | for (i = 0; i < r.nr_split_types; i++) { |
504 | 0 | err = btf_relocate_rewrite_strs(&r, i + r.nr_dist_base_types); |
505 | 0 | if (err) |
506 | 0 | goto err_out; |
507 | 0 | } |
508 | | /* Finally reset base BTF to be base_btf */ |
509 | 0 | btf_set_base_btf(btf, base_btf); |
510 | |
|
511 | 0 | if (id_map) { |
512 | 0 | *id_map = r.id_map; |
513 | 0 | r.id_map = NULL; |
514 | 0 | } |
515 | 0 | err_out: |
516 | 0 | free(r.id_map); |
517 | 0 | free(r.str_map); |
518 | 0 | return err; |
519 | 0 | } |