17c2aad20Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
27c2aad20Sopenharmony_ci
37c2aad20Sopenharmony_ci/*
47c2aad20Sopenharmony_ci * BTF-to-C type converter.
57c2aad20Sopenharmony_ci *
67c2aad20Sopenharmony_ci * Copyright (c) 2019 Facebook
77c2aad20Sopenharmony_ci */
87c2aad20Sopenharmony_ci
97c2aad20Sopenharmony_ci#include <stdbool.h>
107c2aad20Sopenharmony_ci#include <stddef.h>
117c2aad20Sopenharmony_ci#include <stdlib.h>
127c2aad20Sopenharmony_ci#include <string.h>
137c2aad20Sopenharmony_ci#include <ctype.h>
147c2aad20Sopenharmony_ci#include <endian.h>
157c2aad20Sopenharmony_ci#include <errno.h>
167c2aad20Sopenharmony_ci#include <limits.h>
177c2aad20Sopenharmony_ci#include <linux/err.h>
187c2aad20Sopenharmony_ci#include <linux/btf.h>
197c2aad20Sopenharmony_ci#include <linux/kernel.h>
207c2aad20Sopenharmony_ci#include "btf.h"
217c2aad20Sopenharmony_ci#include "hashmap.h"
227c2aad20Sopenharmony_ci#include "libbpf.h"
237c2aad20Sopenharmony_ci#include "libbpf_internal.h"
247c2aad20Sopenharmony_ci
257c2aad20Sopenharmony_cistatic const char PREFIXES[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t";
267c2aad20Sopenharmony_cistatic const size_t PREFIX_CNT = sizeof(PREFIXES) - 1;
277c2aad20Sopenharmony_ci
287c2aad20Sopenharmony_cistatic const char *pfx(int lvl)
297c2aad20Sopenharmony_ci{
307c2aad20Sopenharmony_ci	return lvl >= PREFIX_CNT ? PREFIXES : &PREFIXES[PREFIX_CNT - lvl];
317c2aad20Sopenharmony_ci}
327c2aad20Sopenharmony_ci
337c2aad20Sopenharmony_cienum btf_dump_type_order_state {
347c2aad20Sopenharmony_ci	NOT_ORDERED,
357c2aad20Sopenharmony_ci	ORDERING,
367c2aad20Sopenharmony_ci	ORDERED,
377c2aad20Sopenharmony_ci};
387c2aad20Sopenharmony_ci
397c2aad20Sopenharmony_cienum btf_dump_type_emit_state {
407c2aad20Sopenharmony_ci	NOT_EMITTED,
417c2aad20Sopenharmony_ci	EMITTING,
427c2aad20Sopenharmony_ci	EMITTED,
437c2aad20Sopenharmony_ci};
447c2aad20Sopenharmony_ci
457c2aad20Sopenharmony_ci/* per-type auxiliary state */
467c2aad20Sopenharmony_cistruct btf_dump_type_aux_state {
477c2aad20Sopenharmony_ci	/* topological sorting state */
487c2aad20Sopenharmony_ci	enum btf_dump_type_order_state order_state: 2;
497c2aad20Sopenharmony_ci	/* emitting state used to determine the need for forward declaration */
507c2aad20Sopenharmony_ci	enum btf_dump_type_emit_state emit_state: 2;
517c2aad20Sopenharmony_ci	/* whether forward declaration was already emitted */
527c2aad20Sopenharmony_ci	__u8 fwd_emitted: 1;
537c2aad20Sopenharmony_ci	/* whether unique non-duplicate name was already assigned */
547c2aad20Sopenharmony_ci	__u8 name_resolved: 1;
557c2aad20Sopenharmony_ci	/* whether type is referenced from any other type */
567c2aad20Sopenharmony_ci	__u8 referenced: 1;
577c2aad20Sopenharmony_ci};
587c2aad20Sopenharmony_ci
597c2aad20Sopenharmony_ci/* indent string length; one indent string is added for each indent level */
607c2aad20Sopenharmony_ci#define BTF_DATA_INDENT_STR_LEN			32
617c2aad20Sopenharmony_ci
627c2aad20Sopenharmony_ci/*
637c2aad20Sopenharmony_ci * Common internal data for BTF type data dump operations.
647c2aad20Sopenharmony_ci */
657c2aad20Sopenharmony_cistruct btf_dump_data {
667c2aad20Sopenharmony_ci	const void *data_end;		/* end of valid data to show */
677c2aad20Sopenharmony_ci	bool compact;
687c2aad20Sopenharmony_ci	bool skip_names;
697c2aad20Sopenharmony_ci	bool emit_zeroes;
707c2aad20Sopenharmony_ci	__u8 indent_lvl;	/* base indent level */
717c2aad20Sopenharmony_ci	char indent_str[BTF_DATA_INDENT_STR_LEN];
727c2aad20Sopenharmony_ci	/* below are used during iteration */
737c2aad20Sopenharmony_ci	int depth;
747c2aad20Sopenharmony_ci	bool is_array_member;
757c2aad20Sopenharmony_ci	bool is_array_terminated;
767c2aad20Sopenharmony_ci	bool is_array_char;
777c2aad20Sopenharmony_ci};
787c2aad20Sopenharmony_ci
797c2aad20Sopenharmony_cistruct btf_dump {
807c2aad20Sopenharmony_ci	const struct btf *btf;
817c2aad20Sopenharmony_ci	btf_dump_printf_fn_t printf_fn;
827c2aad20Sopenharmony_ci	void *cb_ctx;
837c2aad20Sopenharmony_ci	int ptr_sz;
847c2aad20Sopenharmony_ci	bool strip_mods;
857c2aad20Sopenharmony_ci	bool skip_anon_defs;
867c2aad20Sopenharmony_ci	int last_id;
877c2aad20Sopenharmony_ci
887c2aad20Sopenharmony_ci	/* per-type auxiliary state */
897c2aad20Sopenharmony_ci	struct btf_dump_type_aux_state *type_states;
907c2aad20Sopenharmony_ci	size_t type_states_cap;
917c2aad20Sopenharmony_ci	/* per-type optional cached unique name, must be freed, if present */
927c2aad20Sopenharmony_ci	const char **cached_names;
937c2aad20Sopenharmony_ci	size_t cached_names_cap;
947c2aad20Sopenharmony_ci
957c2aad20Sopenharmony_ci	/* topo-sorted list of dependent type definitions */
967c2aad20Sopenharmony_ci	__u32 *emit_queue;
977c2aad20Sopenharmony_ci	int emit_queue_cap;
987c2aad20Sopenharmony_ci	int emit_queue_cnt;
997c2aad20Sopenharmony_ci
1007c2aad20Sopenharmony_ci	/*
1017c2aad20Sopenharmony_ci	 * stack of type declarations (e.g., chain of modifiers, arrays,
1027c2aad20Sopenharmony_ci	 * funcs, etc)
1037c2aad20Sopenharmony_ci	 */
1047c2aad20Sopenharmony_ci	__u32 *decl_stack;
1057c2aad20Sopenharmony_ci	int decl_stack_cap;
1067c2aad20Sopenharmony_ci	int decl_stack_cnt;
1077c2aad20Sopenharmony_ci
1087c2aad20Sopenharmony_ci	/* maps struct/union/enum name to a number of name occurrences */
1097c2aad20Sopenharmony_ci	struct hashmap *type_names;
1107c2aad20Sopenharmony_ci	/*
1117c2aad20Sopenharmony_ci	 * maps typedef identifiers and enum value names to a number of such
1127c2aad20Sopenharmony_ci	 * name occurrences
1137c2aad20Sopenharmony_ci	 */
1147c2aad20Sopenharmony_ci	struct hashmap *ident_names;
1157c2aad20Sopenharmony_ci	/*
1167c2aad20Sopenharmony_ci	 * data for typed display; allocated if needed.
1177c2aad20Sopenharmony_ci	 */
1187c2aad20Sopenharmony_ci	struct btf_dump_data *typed_dump;
1197c2aad20Sopenharmony_ci};
1207c2aad20Sopenharmony_ci
1217c2aad20Sopenharmony_cistatic size_t str_hash_fn(long key, void *ctx)
1227c2aad20Sopenharmony_ci{
1237c2aad20Sopenharmony_ci	return str_hash((void *)key);
1247c2aad20Sopenharmony_ci}
1257c2aad20Sopenharmony_ci
1267c2aad20Sopenharmony_cistatic bool str_equal_fn(long a, long b, void *ctx)
1277c2aad20Sopenharmony_ci{
1287c2aad20Sopenharmony_ci	return strcmp((void *)a, (void *)b) == 0;
1297c2aad20Sopenharmony_ci}
1307c2aad20Sopenharmony_ci
1317c2aad20Sopenharmony_cistatic const char *btf_name_of(const struct btf_dump *d, __u32 name_off)
1327c2aad20Sopenharmony_ci{
1337c2aad20Sopenharmony_ci	return btf__name_by_offset(d->btf, name_off);
1347c2aad20Sopenharmony_ci}
1357c2aad20Sopenharmony_ci
1367c2aad20Sopenharmony_cistatic void btf_dump_printf(const struct btf_dump *d, const char *fmt, ...)
1377c2aad20Sopenharmony_ci{
1387c2aad20Sopenharmony_ci	va_list args;
1397c2aad20Sopenharmony_ci
1407c2aad20Sopenharmony_ci	va_start(args, fmt);
1417c2aad20Sopenharmony_ci	d->printf_fn(d->cb_ctx, fmt, args);
1427c2aad20Sopenharmony_ci	va_end(args);
1437c2aad20Sopenharmony_ci}
1447c2aad20Sopenharmony_ci
1457c2aad20Sopenharmony_cistatic int btf_dump_mark_referenced(struct btf_dump *d);
1467c2aad20Sopenharmony_cistatic int btf_dump_resize(struct btf_dump *d);
1477c2aad20Sopenharmony_ci
1487c2aad20Sopenharmony_cistruct btf_dump *btf_dump__new(const struct btf *btf,
1497c2aad20Sopenharmony_ci			       btf_dump_printf_fn_t printf_fn,
1507c2aad20Sopenharmony_ci			       void *ctx,
1517c2aad20Sopenharmony_ci			       const struct btf_dump_opts *opts)
1527c2aad20Sopenharmony_ci{
1537c2aad20Sopenharmony_ci	struct btf_dump *d;
1547c2aad20Sopenharmony_ci	int err;
1557c2aad20Sopenharmony_ci
1567c2aad20Sopenharmony_ci	if (!OPTS_VALID(opts, btf_dump_opts))
1577c2aad20Sopenharmony_ci		return libbpf_err_ptr(-EINVAL);
1587c2aad20Sopenharmony_ci
1597c2aad20Sopenharmony_ci	if (!printf_fn)
1607c2aad20Sopenharmony_ci		return libbpf_err_ptr(-EINVAL);
1617c2aad20Sopenharmony_ci
1627c2aad20Sopenharmony_ci	d = calloc(1, sizeof(struct btf_dump));
1637c2aad20Sopenharmony_ci	if (!d)
1647c2aad20Sopenharmony_ci		return libbpf_err_ptr(-ENOMEM);
1657c2aad20Sopenharmony_ci
1667c2aad20Sopenharmony_ci	d->btf = btf;
1677c2aad20Sopenharmony_ci	d->printf_fn = printf_fn;
1687c2aad20Sopenharmony_ci	d->cb_ctx = ctx;
1697c2aad20Sopenharmony_ci	d->ptr_sz = btf__pointer_size(btf) ? : sizeof(void *);
1707c2aad20Sopenharmony_ci
1717c2aad20Sopenharmony_ci	d->type_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
1727c2aad20Sopenharmony_ci	if (IS_ERR(d->type_names)) {
1737c2aad20Sopenharmony_ci		err = PTR_ERR(d->type_names);
1747c2aad20Sopenharmony_ci		d->type_names = NULL;
1757c2aad20Sopenharmony_ci		goto err;
1767c2aad20Sopenharmony_ci	}
1777c2aad20Sopenharmony_ci	d->ident_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
1787c2aad20Sopenharmony_ci	if (IS_ERR(d->ident_names)) {
1797c2aad20Sopenharmony_ci		err = PTR_ERR(d->ident_names);
1807c2aad20Sopenharmony_ci		d->ident_names = NULL;
1817c2aad20Sopenharmony_ci		goto err;
1827c2aad20Sopenharmony_ci	}
1837c2aad20Sopenharmony_ci
1847c2aad20Sopenharmony_ci	err = btf_dump_resize(d);
1857c2aad20Sopenharmony_ci	if (err)
1867c2aad20Sopenharmony_ci		goto err;
1877c2aad20Sopenharmony_ci
1887c2aad20Sopenharmony_ci	return d;
1897c2aad20Sopenharmony_cierr:
1907c2aad20Sopenharmony_ci	btf_dump__free(d);
1917c2aad20Sopenharmony_ci	return libbpf_err_ptr(err);
1927c2aad20Sopenharmony_ci}
1937c2aad20Sopenharmony_ci
1947c2aad20Sopenharmony_cistatic int btf_dump_resize(struct btf_dump *d)
1957c2aad20Sopenharmony_ci{
1967c2aad20Sopenharmony_ci	int err, last_id = btf__type_cnt(d->btf) - 1;
1977c2aad20Sopenharmony_ci
1987c2aad20Sopenharmony_ci	if (last_id <= d->last_id)
1997c2aad20Sopenharmony_ci		return 0;
2007c2aad20Sopenharmony_ci
2017c2aad20Sopenharmony_ci	if (libbpf_ensure_mem((void **)&d->type_states, &d->type_states_cap,
2027c2aad20Sopenharmony_ci			      sizeof(*d->type_states), last_id + 1))
2037c2aad20Sopenharmony_ci		return -ENOMEM;
2047c2aad20Sopenharmony_ci	if (libbpf_ensure_mem((void **)&d->cached_names, &d->cached_names_cap,
2057c2aad20Sopenharmony_ci			      sizeof(*d->cached_names), last_id + 1))
2067c2aad20Sopenharmony_ci		return -ENOMEM;
2077c2aad20Sopenharmony_ci
2087c2aad20Sopenharmony_ci	if (d->last_id == 0) {
2097c2aad20Sopenharmony_ci		/* VOID is special */
2107c2aad20Sopenharmony_ci		d->type_states[0].order_state = ORDERED;
2117c2aad20Sopenharmony_ci		d->type_states[0].emit_state = EMITTED;
2127c2aad20Sopenharmony_ci	}
2137c2aad20Sopenharmony_ci
2147c2aad20Sopenharmony_ci	/* eagerly determine referenced types for anon enums */
2157c2aad20Sopenharmony_ci	err = btf_dump_mark_referenced(d);
2167c2aad20Sopenharmony_ci	if (err)
2177c2aad20Sopenharmony_ci		return err;
2187c2aad20Sopenharmony_ci
2197c2aad20Sopenharmony_ci	d->last_id = last_id;
2207c2aad20Sopenharmony_ci	return 0;
2217c2aad20Sopenharmony_ci}
2227c2aad20Sopenharmony_ci
2237c2aad20Sopenharmony_cistatic void btf_dump_free_names(struct hashmap *map)
2247c2aad20Sopenharmony_ci{
2257c2aad20Sopenharmony_ci	size_t bkt;
2267c2aad20Sopenharmony_ci	struct hashmap_entry *cur;
2277c2aad20Sopenharmony_ci
2287c2aad20Sopenharmony_ci	hashmap__for_each_entry(map, cur, bkt)
2297c2aad20Sopenharmony_ci		free((void *)cur->pkey);
2307c2aad20Sopenharmony_ci
2317c2aad20Sopenharmony_ci	hashmap__free(map);
2327c2aad20Sopenharmony_ci}
2337c2aad20Sopenharmony_ci
2347c2aad20Sopenharmony_civoid btf_dump__free(struct btf_dump *d)
2357c2aad20Sopenharmony_ci{
2367c2aad20Sopenharmony_ci	int i;
2377c2aad20Sopenharmony_ci
2387c2aad20Sopenharmony_ci	if (IS_ERR_OR_NULL(d))
2397c2aad20Sopenharmony_ci		return;
2407c2aad20Sopenharmony_ci
2417c2aad20Sopenharmony_ci	free(d->type_states);
2427c2aad20Sopenharmony_ci	if (d->cached_names) {
2437c2aad20Sopenharmony_ci		/* any set cached name is owned by us and should be freed */
2447c2aad20Sopenharmony_ci		for (i = 0; i <= d->last_id; i++) {
2457c2aad20Sopenharmony_ci			if (d->cached_names[i])
2467c2aad20Sopenharmony_ci				free((void *)d->cached_names[i]);
2477c2aad20Sopenharmony_ci		}
2487c2aad20Sopenharmony_ci	}
2497c2aad20Sopenharmony_ci	free(d->cached_names);
2507c2aad20Sopenharmony_ci	free(d->emit_queue);
2517c2aad20Sopenharmony_ci	free(d->decl_stack);
2527c2aad20Sopenharmony_ci	btf_dump_free_names(d->type_names);
2537c2aad20Sopenharmony_ci	btf_dump_free_names(d->ident_names);
2547c2aad20Sopenharmony_ci
2557c2aad20Sopenharmony_ci	free(d);
2567c2aad20Sopenharmony_ci}
2577c2aad20Sopenharmony_ci
2587c2aad20Sopenharmony_cistatic int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr);
2597c2aad20Sopenharmony_cistatic void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id);
2607c2aad20Sopenharmony_ci
2617c2aad20Sopenharmony_ci/*
2627c2aad20Sopenharmony_ci * Dump BTF type in a compilable C syntax, including all the necessary
2637c2aad20Sopenharmony_ci * dependent types, necessary for compilation. If some of the dependent types
2647c2aad20Sopenharmony_ci * were already emitted as part of previous btf_dump__dump_type() invocation
2657c2aad20Sopenharmony_ci * for another type, they won't be emitted again. This API allows callers to
2667c2aad20Sopenharmony_ci * filter out BTF types according to user-defined criterias and emitted only
2677c2aad20Sopenharmony_ci * minimal subset of types, necessary to compile everything. Full struct/union
2687c2aad20Sopenharmony_ci * definitions will still be emitted, even if the only usage is through
2697c2aad20Sopenharmony_ci * pointer and could be satisfied with just a forward declaration.
2707c2aad20Sopenharmony_ci *
2717c2aad20Sopenharmony_ci * Dumping is done in two high-level passes:
2727c2aad20Sopenharmony_ci *   1. Topologically sort type definitions to satisfy C rules of compilation.
2737c2aad20Sopenharmony_ci *   2. Emit type definitions in C syntax.
2747c2aad20Sopenharmony_ci *
2757c2aad20Sopenharmony_ci * Returns 0 on success; <0, otherwise.
2767c2aad20Sopenharmony_ci */
2777c2aad20Sopenharmony_ciint btf_dump__dump_type(struct btf_dump *d, __u32 id)
2787c2aad20Sopenharmony_ci{
2797c2aad20Sopenharmony_ci	int err, i;
2807c2aad20Sopenharmony_ci
2817c2aad20Sopenharmony_ci	if (id >= btf__type_cnt(d->btf))
2827c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
2837c2aad20Sopenharmony_ci
2847c2aad20Sopenharmony_ci	err = btf_dump_resize(d);
2857c2aad20Sopenharmony_ci	if (err)
2867c2aad20Sopenharmony_ci		return libbpf_err(err);
2877c2aad20Sopenharmony_ci
2887c2aad20Sopenharmony_ci	d->emit_queue_cnt = 0;
2897c2aad20Sopenharmony_ci	err = btf_dump_order_type(d, id, false);
2907c2aad20Sopenharmony_ci	if (err < 0)
2917c2aad20Sopenharmony_ci		return libbpf_err(err);
2927c2aad20Sopenharmony_ci
2937c2aad20Sopenharmony_ci	for (i = 0; i < d->emit_queue_cnt; i++)
2947c2aad20Sopenharmony_ci		btf_dump_emit_type(d, d->emit_queue[i], 0 /*top-level*/);
2957c2aad20Sopenharmony_ci
2967c2aad20Sopenharmony_ci	return 0;
2977c2aad20Sopenharmony_ci}
2987c2aad20Sopenharmony_ci
2997c2aad20Sopenharmony_ci/*
3007c2aad20Sopenharmony_ci * Mark all types that are referenced from any other type. This is used to
3017c2aad20Sopenharmony_ci * determine top-level anonymous enums that need to be emitted as an
3027c2aad20Sopenharmony_ci * independent type declarations.
3037c2aad20Sopenharmony_ci * Anonymous enums come in two flavors: either embedded in a struct's field
3047c2aad20Sopenharmony_ci * definition, in which case they have to be declared inline as part of field
3057c2aad20Sopenharmony_ci * type declaration; or as a top-level anonymous enum, typically used for
3067c2aad20Sopenharmony_ci * declaring global constants. It's impossible to distinguish between two
3077c2aad20Sopenharmony_ci * without knowning whether given enum type was referenced from other type:
3087c2aad20Sopenharmony_ci * top-level anonymous enum won't be referenced by anything, while embedded
3097c2aad20Sopenharmony_ci * one will.
3107c2aad20Sopenharmony_ci */
3117c2aad20Sopenharmony_cistatic int btf_dump_mark_referenced(struct btf_dump *d)
3127c2aad20Sopenharmony_ci{
3137c2aad20Sopenharmony_ci	int i, j, n = btf__type_cnt(d->btf);
3147c2aad20Sopenharmony_ci	const struct btf_type *t;
3157c2aad20Sopenharmony_ci	__u16 vlen;
3167c2aad20Sopenharmony_ci
3177c2aad20Sopenharmony_ci	for (i = d->last_id + 1; i < n; i++) {
3187c2aad20Sopenharmony_ci		t = btf__type_by_id(d->btf, i);
3197c2aad20Sopenharmony_ci		vlen = btf_vlen(t);
3207c2aad20Sopenharmony_ci
3217c2aad20Sopenharmony_ci		switch (btf_kind(t)) {
3227c2aad20Sopenharmony_ci		case BTF_KIND_INT:
3237c2aad20Sopenharmony_ci		case BTF_KIND_ENUM:
3247c2aad20Sopenharmony_ci		case BTF_KIND_ENUM64:
3257c2aad20Sopenharmony_ci		case BTF_KIND_FWD:
3267c2aad20Sopenharmony_ci		case BTF_KIND_FLOAT:
3277c2aad20Sopenharmony_ci			break;
3287c2aad20Sopenharmony_ci
3297c2aad20Sopenharmony_ci		case BTF_KIND_VOLATILE:
3307c2aad20Sopenharmony_ci		case BTF_KIND_CONST:
3317c2aad20Sopenharmony_ci		case BTF_KIND_RESTRICT:
3327c2aad20Sopenharmony_ci		case BTF_KIND_PTR:
3337c2aad20Sopenharmony_ci		case BTF_KIND_TYPEDEF:
3347c2aad20Sopenharmony_ci		case BTF_KIND_FUNC:
3357c2aad20Sopenharmony_ci		case BTF_KIND_VAR:
3367c2aad20Sopenharmony_ci		case BTF_KIND_DECL_TAG:
3377c2aad20Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
3387c2aad20Sopenharmony_ci			d->type_states[t->type].referenced = 1;
3397c2aad20Sopenharmony_ci			break;
3407c2aad20Sopenharmony_ci
3417c2aad20Sopenharmony_ci		case BTF_KIND_ARRAY: {
3427c2aad20Sopenharmony_ci			const struct btf_array *a = btf_array(t);
3437c2aad20Sopenharmony_ci
3447c2aad20Sopenharmony_ci			d->type_states[a->index_type].referenced = 1;
3457c2aad20Sopenharmony_ci			d->type_states[a->type].referenced = 1;
3467c2aad20Sopenharmony_ci			break;
3477c2aad20Sopenharmony_ci		}
3487c2aad20Sopenharmony_ci		case BTF_KIND_STRUCT:
3497c2aad20Sopenharmony_ci		case BTF_KIND_UNION: {
3507c2aad20Sopenharmony_ci			const struct btf_member *m = btf_members(t);
3517c2aad20Sopenharmony_ci
3527c2aad20Sopenharmony_ci			for (j = 0; j < vlen; j++, m++)
3537c2aad20Sopenharmony_ci				d->type_states[m->type].referenced = 1;
3547c2aad20Sopenharmony_ci			break;
3557c2aad20Sopenharmony_ci		}
3567c2aad20Sopenharmony_ci		case BTF_KIND_FUNC_PROTO: {
3577c2aad20Sopenharmony_ci			const struct btf_param *p = btf_params(t);
3587c2aad20Sopenharmony_ci
3597c2aad20Sopenharmony_ci			for (j = 0; j < vlen; j++, p++)
3607c2aad20Sopenharmony_ci				d->type_states[p->type].referenced = 1;
3617c2aad20Sopenharmony_ci			break;
3627c2aad20Sopenharmony_ci		}
3637c2aad20Sopenharmony_ci		case BTF_KIND_DATASEC: {
3647c2aad20Sopenharmony_ci			const struct btf_var_secinfo *v = btf_var_secinfos(t);
3657c2aad20Sopenharmony_ci
3667c2aad20Sopenharmony_ci			for (j = 0; j < vlen; j++, v++)
3677c2aad20Sopenharmony_ci				d->type_states[v->type].referenced = 1;
3687c2aad20Sopenharmony_ci			break;
3697c2aad20Sopenharmony_ci		}
3707c2aad20Sopenharmony_ci		default:
3717c2aad20Sopenharmony_ci			return -EINVAL;
3727c2aad20Sopenharmony_ci		}
3737c2aad20Sopenharmony_ci	}
3747c2aad20Sopenharmony_ci	return 0;
3757c2aad20Sopenharmony_ci}
3767c2aad20Sopenharmony_ci
3777c2aad20Sopenharmony_cistatic int btf_dump_add_emit_queue_id(struct btf_dump *d, __u32 id)
3787c2aad20Sopenharmony_ci{
3797c2aad20Sopenharmony_ci	__u32 *new_queue;
3807c2aad20Sopenharmony_ci	size_t new_cap;
3817c2aad20Sopenharmony_ci
3827c2aad20Sopenharmony_ci	if (d->emit_queue_cnt >= d->emit_queue_cap) {
3837c2aad20Sopenharmony_ci		new_cap = max(16, d->emit_queue_cap * 3 / 2);
3847c2aad20Sopenharmony_ci		new_queue = libbpf_reallocarray(d->emit_queue, new_cap, sizeof(new_queue[0]));
3857c2aad20Sopenharmony_ci		if (!new_queue)
3867c2aad20Sopenharmony_ci			return -ENOMEM;
3877c2aad20Sopenharmony_ci		d->emit_queue = new_queue;
3887c2aad20Sopenharmony_ci		d->emit_queue_cap = new_cap;
3897c2aad20Sopenharmony_ci	}
3907c2aad20Sopenharmony_ci
3917c2aad20Sopenharmony_ci	d->emit_queue[d->emit_queue_cnt++] = id;
3927c2aad20Sopenharmony_ci	return 0;
3937c2aad20Sopenharmony_ci}
3947c2aad20Sopenharmony_ci
3957c2aad20Sopenharmony_ci/*
3967c2aad20Sopenharmony_ci * Determine order of emitting dependent types and specified type to satisfy
3977c2aad20Sopenharmony_ci * C compilation rules.  This is done through topological sorting with an
3987c2aad20Sopenharmony_ci * additional complication which comes from C rules. The main idea for C is
3997c2aad20Sopenharmony_ci * that if some type is "embedded" into a struct/union, it's size needs to be
4007c2aad20Sopenharmony_ci * known at the time of definition of containing type. E.g., for:
4017c2aad20Sopenharmony_ci *
4027c2aad20Sopenharmony_ci *	struct A {};
4037c2aad20Sopenharmony_ci *	struct B { struct A x; }
4047c2aad20Sopenharmony_ci *
4057c2aad20Sopenharmony_ci * struct A *HAS* to be defined before struct B, because it's "embedded",
4067c2aad20Sopenharmony_ci * i.e., it is part of struct B layout. But in the following case:
4077c2aad20Sopenharmony_ci *
4087c2aad20Sopenharmony_ci *	struct A;
4097c2aad20Sopenharmony_ci *	struct B { struct A *x; }
4107c2aad20Sopenharmony_ci *	struct A {};
4117c2aad20Sopenharmony_ci *
4127c2aad20Sopenharmony_ci * it's enough to just have a forward declaration of struct A at the time of
4137c2aad20Sopenharmony_ci * struct B definition, as struct B has a pointer to struct A, so the size of
4147c2aad20Sopenharmony_ci * field x is known without knowing struct A size: it's sizeof(void *).
4157c2aad20Sopenharmony_ci *
4167c2aad20Sopenharmony_ci * Unfortunately, there are some trickier cases we need to handle, e.g.:
4177c2aad20Sopenharmony_ci *
4187c2aad20Sopenharmony_ci *	struct A {}; // if this was forward-declaration: compilation error
4197c2aad20Sopenharmony_ci *	struct B {
4207c2aad20Sopenharmony_ci *		struct { // anonymous struct
4217c2aad20Sopenharmony_ci *			struct A y;
4227c2aad20Sopenharmony_ci *		} *x;
4237c2aad20Sopenharmony_ci *	};
4247c2aad20Sopenharmony_ci *
4257c2aad20Sopenharmony_ci * In this case, struct B's field x is a pointer, so it's size is known
4267c2aad20Sopenharmony_ci * regardless of the size of (anonymous) struct it points to. But because this
4277c2aad20Sopenharmony_ci * struct is anonymous and thus defined inline inside struct B, *and* it
4287c2aad20Sopenharmony_ci * embeds struct A, compiler requires full definition of struct A to be known
4297c2aad20Sopenharmony_ci * before struct B can be defined. This creates a transitive dependency
4307c2aad20Sopenharmony_ci * between struct A and struct B. If struct A was forward-declared before
4317c2aad20Sopenharmony_ci * struct B definition and fully defined after struct B definition, that would
4327c2aad20Sopenharmony_ci * trigger compilation error.
4337c2aad20Sopenharmony_ci *
4347c2aad20Sopenharmony_ci * All this means that while we are doing topological sorting on BTF type
4357c2aad20Sopenharmony_ci * graph, we need to determine relationships between different types (graph
4367c2aad20Sopenharmony_ci * nodes):
4377c2aad20Sopenharmony_ci *   - weak link (relationship) between X and Y, if Y *CAN* be
4387c2aad20Sopenharmony_ci *   forward-declared at the point of X definition;
4397c2aad20Sopenharmony_ci *   - strong link, if Y *HAS* to be fully-defined before X can be defined.
4407c2aad20Sopenharmony_ci *
4417c2aad20Sopenharmony_ci * The rule is as follows. Given a chain of BTF types from X to Y, if there is
4427c2aad20Sopenharmony_ci * BTF_KIND_PTR type in the chain and at least one non-anonymous type
4437c2aad20Sopenharmony_ci * Z (excluding X, including Y), then link is weak. Otherwise, it's strong.
4447c2aad20Sopenharmony_ci * Weak/strong relationship is determined recursively during DFS traversal and
4457c2aad20Sopenharmony_ci * is returned as a result from btf_dump_order_type().
4467c2aad20Sopenharmony_ci *
4477c2aad20Sopenharmony_ci * btf_dump_order_type() is trying to avoid unnecessary forward declarations,
4487c2aad20Sopenharmony_ci * but it is not guaranteeing that no extraneous forward declarations will be
4497c2aad20Sopenharmony_ci * emitted.
4507c2aad20Sopenharmony_ci *
4517c2aad20Sopenharmony_ci * To avoid extra work, algorithm marks some of BTF types as ORDERED, when
4527c2aad20Sopenharmony_ci * it's done with them, but not for all (e.g., VOLATILE, CONST, RESTRICT,
4537c2aad20Sopenharmony_ci * ARRAY, FUNC_PROTO), as weak/strong semantics for those depends on the
4547c2aad20Sopenharmony_ci * entire graph path, so depending where from one came to that BTF type, it
4557c2aad20Sopenharmony_ci * might cause weak or strong ordering. For types like STRUCT/UNION/INT/ENUM,
4567c2aad20Sopenharmony_ci * once they are processed, there is no need to do it again, so they are
4577c2aad20Sopenharmony_ci * marked as ORDERED. We can mark PTR as ORDERED as well, as it semi-forces
4587c2aad20Sopenharmony_ci * weak link, unless subsequent referenced STRUCT/UNION/ENUM is anonymous. But
4597c2aad20Sopenharmony_ci * in any case, once those are processed, no need to do it again, as the
4607c2aad20Sopenharmony_ci * result won't change.
4617c2aad20Sopenharmony_ci *
4627c2aad20Sopenharmony_ci * Returns:
4637c2aad20Sopenharmony_ci *   - 1, if type is part of strong link (so there is strong topological
4647c2aad20Sopenharmony_ci *   ordering requirements);
4657c2aad20Sopenharmony_ci *   - 0, if type is part of weak link (so can be satisfied through forward
4667c2aad20Sopenharmony_ci *   declaration);
4677c2aad20Sopenharmony_ci *   - <0, on error (e.g., unsatisfiable type loop detected).
4687c2aad20Sopenharmony_ci */
4697c2aad20Sopenharmony_cistatic int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
4707c2aad20Sopenharmony_ci{
4717c2aad20Sopenharmony_ci	/*
4727c2aad20Sopenharmony_ci	 * Order state is used to detect strong link cycles, but only for BTF
4737c2aad20Sopenharmony_ci	 * kinds that are or could be an independent definition (i.e.,
4747c2aad20Sopenharmony_ci	 * stand-alone fwd decl, enum, typedef, struct, union). Ptrs, arrays,
4757c2aad20Sopenharmony_ci	 * func_protos, modifiers are just means to get to these definitions.
4767c2aad20Sopenharmony_ci	 * Int/void don't need definitions, they are assumed to be always
4777c2aad20Sopenharmony_ci	 * properly defined.  We also ignore datasec, var, and funcs for now.
4787c2aad20Sopenharmony_ci	 * So for all non-defining kinds, we never even set ordering state,
4797c2aad20Sopenharmony_ci	 * for defining kinds we set ORDERING and subsequently ORDERED if it
4807c2aad20Sopenharmony_ci	 * forms a strong link.
4817c2aad20Sopenharmony_ci	 */
4827c2aad20Sopenharmony_ci	struct btf_dump_type_aux_state *tstate = &d->type_states[id];
4837c2aad20Sopenharmony_ci	const struct btf_type *t;
4847c2aad20Sopenharmony_ci	__u16 vlen;
4857c2aad20Sopenharmony_ci	int err, i;
4867c2aad20Sopenharmony_ci
4877c2aad20Sopenharmony_ci	/* return true, letting typedefs know that it's ok to be emitted */
4887c2aad20Sopenharmony_ci	if (tstate->order_state == ORDERED)
4897c2aad20Sopenharmony_ci		return 1;
4907c2aad20Sopenharmony_ci
4917c2aad20Sopenharmony_ci	t = btf__type_by_id(d->btf, id);
4927c2aad20Sopenharmony_ci
4937c2aad20Sopenharmony_ci	if (tstate->order_state == ORDERING) {
4947c2aad20Sopenharmony_ci		/* type loop, but resolvable through fwd declaration */
4957c2aad20Sopenharmony_ci		if (btf_is_composite(t) && through_ptr && t->name_off != 0)
4967c2aad20Sopenharmony_ci			return 0;
4977c2aad20Sopenharmony_ci		pr_warn("unsatisfiable type cycle, id:[%u]\n", id);
4987c2aad20Sopenharmony_ci		return -ELOOP;
4997c2aad20Sopenharmony_ci	}
5007c2aad20Sopenharmony_ci
5017c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
5027c2aad20Sopenharmony_ci	case BTF_KIND_INT:
5037c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
5047c2aad20Sopenharmony_ci		tstate->order_state = ORDERED;
5057c2aad20Sopenharmony_ci		return 0;
5067c2aad20Sopenharmony_ci
5077c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
5087c2aad20Sopenharmony_ci		err = btf_dump_order_type(d, t->type, true);
5097c2aad20Sopenharmony_ci		tstate->order_state = ORDERED;
5107c2aad20Sopenharmony_ci		return err;
5117c2aad20Sopenharmony_ci
5127c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
5137c2aad20Sopenharmony_ci		return btf_dump_order_type(d, btf_array(t)->type, false);
5147c2aad20Sopenharmony_ci
5157c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
5167c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
5177c2aad20Sopenharmony_ci		const struct btf_member *m = btf_members(t);
5187c2aad20Sopenharmony_ci		/*
5197c2aad20Sopenharmony_ci		 * struct/union is part of strong link, only if it's embedded
5207c2aad20Sopenharmony_ci		 * (so no ptr in a path) or it's anonymous (so has to be
5217c2aad20Sopenharmony_ci		 * defined inline, even if declared through ptr)
5227c2aad20Sopenharmony_ci		 */
5237c2aad20Sopenharmony_ci		if (through_ptr && t->name_off != 0)
5247c2aad20Sopenharmony_ci			return 0;
5257c2aad20Sopenharmony_ci
5267c2aad20Sopenharmony_ci		tstate->order_state = ORDERING;
5277c2aad20Sopenharmony_ci
5287c2aad20Sopenharmony_ci		vlen = btf_vlen(t);
5297c2aad20Sopenharmony_ci		for (i = 0; i < vlen; i++, m++) {
5307c2aad20Sopenharmony_ci			err = btf_dump_order_type(d, m->type, false);
5317c2aad20Sopenharmony_ci			if (err < 0)
5327c2aad20Sopenharmony_ci				return err;
5337c2aad20Sopenharmony_ci		}
5347c2aad20Sopenharmony_ci
5357c2aad20Sopenharmony_ci		if (t->name_off != 0) {
5367c2aad20Sopenharmony_ci			err = btf_dump_add_emit_queue_id(d, id);
5377c2aad20Sopenharmony_ci			if (err < 0)
5387c2aad20Sopenharmony_ci				return err;
5397c2aad20Sopenharmony_ci		}
5407c2aad20Sopenharmony_ci
5417c2aad20Sopenharmony_ci		tstate->order_state = ORDERED;
5427c2aad20Sopenharmony_ci		return 1;
5437c2aad20Sopenharmony_ci	}
5447c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
5457c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
5467c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
5477c2aad20Sopenharmony_ci		/*
5487c2aad20Sopenharmony_ci		 * non-anonymous or non-referenced enums are top-level
5497c2aad20Sopenharmony_ci		 * declarations and should be emitted. Same logic can be
5507c2aad20Sopenharmony_ci		 * applied to FWDs, it won't hurt anyways.
5517c2aad20Sopenharmony_ci		 */
5527c2aad20Sopenharmony_ci		if (t->name_off != 0 || !tstate->referenced) {
5537c2aad20Sopenharmony_ci			err = btf_dump_add_emit_queue_id(d, id);
5547c2aad20Sopenharmony_ci			if (err)
5557c2aad20Sopenharmony_ci				return err;
5567c2aad20Sopenharmony_ci		}
5577c2aad20Sopenharmony_ci		tstate->order_state = ORDERED;
5587c2aad20Sopenharmony_ci		return 1;
5597c2aad20Sopenharmony_ci
5607c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF: {
5617c2aad20Sopenharmony_ci		int is_strong;
5627c2aad20Sopenharmony_ci
5637c2aad20Sopenharmony_ci		is_strong = btf_dump_order_type(d, t->type, through_ptr);
5647c2aad20Sopenharmony_ci		if (is_strong < 0)
5657c2aad20Sopenharmony_ci			return is_strong;
5667c2aad20Sopenharmony_ci
5677c2aad20Sopenharmony_ci		/* typedef is similar to struct/union w.r.t. fwd-decls */
5687c2aad20Sopenharmony_ci		if (through_ptr && !is_strong)
5697c2aad20Sopenharmony_ci			return 0;
5707c2aad20Sopenharmony_ci
5717c2aad20Sopenharmony_ci		/* typedef is always a named definition */
5727c2aad20Sopenharmony_ci		err = btf_dump_add_emit_queue_id(d, id);
5737c2aad20Sopenharmony_ci		if (err)
5747c2aad20Sopenharmony_ci			return err;
5757c2aad20Sopenharmony_ci
5767c2aad20Sopenharmony_ci		d->type_states[id].order_state = ORDERED;
5777c2aad20Sopenharmony_ci		return 1;
5787c2aad20Sopenharmony_ci	}
5797c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
5807c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
5817c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
5827c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
5837c2aad20Sopenharmony_ci		return btf_dump_order_type(d, t->type, through_ptr);
5847c2aad20Sopenharmony_ci
5857c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
5867c2aad20Sopenharmony_ci		const struct btf_param *p = btf_params(t);
5877c2aad20Sopenharmony_ci		bool is_strong;
5887c2aad20Sopenharmony_ci
5897c2aad20Sopenharmony_ci		err = btf_dump_order_type(d, t->type, through_ptr);
5907c2aad20Sopenharmony_ci		if (err < 0)
5917c2aad20Sopenharmony_ci			return err;
5927c2aad20Sopenharmony_ci		is_strong = err > 0;
5937c2aad20Sopenharmony_ci
5947c2aad20Sopenharmony_ci		vlen = btf_vlen(t);
5957c2aad20Sopenharmony_ci		for (i = 0; i < vlen; i++, p++) {
5967c2aad20Sopenharmony_ci			err = btf_dump_order_type(d, p->type, through_ptr);
5977c2aad20Sopenharmony_ci			if (err < 0)
5987c2aad20Sopenharmony_ci				return err;
5997c2aad20Sopenharmony_ci			if (err > 0)
6007c2aad20Sopenharmony_ci				is_strong = true;
6017c2aad20Sopenharmony_ci		}
6027c2aad20Sopenharmony_ci		return is_strong;
6037c2aad20Sopenharmony_ci	}
6047c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
6057c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
6067c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC:
6077c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
6087c2aad20Sopenharmony_ci		d->type_states[id].order_state = ORDERED;
6097c2aad20Sopenharmony_ci		return 0;
6107c2aad20Sopenharmony_ci
6117c2aad20Sopenharmony_ci	default:
6127c2aad20Sopenharmony_ci		return -EINVAL;
6137c2aad20Sopenharmony_ci	}
6147c2aad20Sopenharmony_ci}
6157c2aad20Sopenharmony_ci
6167c2aad20Sopenharmony_cistatic void btf_dump_emit_missing_aliases(struct btf_dump *d, __u32 id,
6177c2aad20Sopenharmony_ci					  const struct btf_type *t);
6187c2aad20Sopenharmony_ci
6197c2aad20Sopenharmony_cistatic void btf_dump_emit_struct_fwd(struct btf_dump *d, __u32 id,
6207c2aad20Sopenharmony_ci				     const struct btf_type *t);
6217c2aad20Sopenharmony_cistatic void btf_dump_emit_struct_def(struct btf_dump *d, __u32 id,
6227c2aad20Sopenharmony_ci				     const struct btf_type *t, int lvl);
6237c2aad20Sopenharmony_ci
6247c2aad20Sopenharmony_cistatic void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
6257c2aad20Sopenharmony_ci				   const struct btf_type *t);
6267c2aad20Sopenharmony_cistatic void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
6277c2aad20Sopenharmony_ci				   const struct btf_type *t, int lvl);
6287c2aad20Sopenharmony_ci
6297c2aad20Sopenharmony_cistatic void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
6307c2aad20Sopenharmony_ci				  const struct btf_type *t);
6317c2aad20Sopenharmony_ci
6327c2aad20Sopenharmony_cistatic void btf_dump_emit_typedef_def(struct btf_dump *d, __u32 id,
6337c2aad20Sopenharmony_ci				      const struct btf_type *t, int lvl);
6347c2aad20Sopenharmony_ci
6357c2aad20Sopenharmony_ci/* a local view into a shared stack */
6367c2aad20Sopenharmony_cistruct id_stack {
6377c2aad20Sopenharmony_ci	const __u32 *ids;
6387c2aad20Sopenharmony_ci	int cnt;
6397c2aad20Sopenharmony_ci};
6407c2aad20Sopenharmony_ci
6417c2aad20Sopenharmony_cistatic void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
6427c2aad20Sopenharmony_ci				    const char *fname, int lvl);
6437c2aad20Sopenharmony_cistatic void btf_dump_emit_type_chain(struct btf_dump *d,
6447c2aad20Sopenharmony_ci				     struct id_stack *decl_stack,
6457c2aad20Sopenharmony_ci				     const char *fname, int lvl);
6467c2aad20Sopenharmony_ci
6477c2aad20Sopenharmony_cistatic const char *btf_dump_type_name(struct btf_dump *d, __u32 id);
6487c2aad20Sopenharmony_cistatic const char *btf_dump_ident_name(struct btf_dump *d, __u32 id);
6497c2aad20Sopenharmony_cistatic size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
6507c2aad20Sopenharmony_ci				 const char *orig_name);
6517c2aad20Sopenharmony_ci
6527c2aad20Sopenharmony_cistatic bool btf_dump_is_blacklisted(struct btf_dump *d, __u32 id)
6537c2aad20Sopenharmony_ci{
6547c2aad20Sopenharmony_ci	const struct btf_type *t = btf__type_by_id(d->btf, id);
6557c2aad20Sopenharmony_ci
6567c2aad20Sopenharmony_ci	/* __builtin_va_list is a compiler built-in, which causes compilation
6577c2aad20Sopenharmony_ci	 * errors, when compiling w/ different compiler, then used to compile
6587c2aad20Sopenharmony_ci	 * original code (e.g., GCC to compile kernel, Clang to use generated
6597c2aad20Sopenharmony_ci	 * C header from BTF). As it is built-in, it should be already defined
6607c2aad20Sopenharmony_ci	 * properly internally in compiler.
6617c2aad20Sopenharmony_ci	 */
6627c2aad20Sopenharmony_ci	if (t->name_off == 0)
6637c2aad20Sopenharmony_ci		return false;
6647c2aad20Sopenharmony_ci	return strcmp(btf_name_of(d, t->name_off), "__builtin_va_list") == 0;
6657c2aad20Sopenharmony_ci}
6667c2aad20Sopenharmony_ci
6677c2aad20Sopenharmony_ci/*
6687c2aad20Sopenharmony_ci * Emit C-syntax definitions of types from chains of BTF types.
6697c2aad20Sopenharmony_ci *
6707c2aad20Sopenharmony_ci * High-level handling of determining necessary forward declarations are handled
6717c2aad20Sopenharmony_ci * by btf_dump_emit_type() itself, but all nitty-gritty details of emitting type
6727c2aad20Sopenharmony_ci * declarations/definitions in C syntax  are handled by a combo of
6737c2aad20Sopenharmony_ci * btf_dump_emit_type_decl()/btf_dump_emit_type_chain() w/ delegation to
6747c2aad20Sopenharmony_ci * corresponding btf_dump_emit_*_{def,fwd}() functions.
6757c2aad20Sopenharmony_ci *
6767c2aad20Sopenharmony_ci * We also keep track of "containing struct/union type ID" to determine when
6777c2aad20Sopenharmony_ci * we reference it from inside and thus can avoid emitting unnecessary forward
6787c2aad20Sopenharmony_ci * declaration.
6797c2aad20Sopenharmony_ci *
6807c2aad20Sopenharmony_ci * This algorithm is designed in such a way, that even if some error occurs
6817c2aad20Sopenharmony_ci * (either technical, e.g., out of memory, or logical, i.e., malformed BTF
6827c2aad20Sopenharmony_ci * that doesn't comply to C rules completely), algorithm will try to proceed
6837c2aad20Sopenharmony_ci * and produce as much meaningful output as possible.
6847c2aad20Sopenharmony_ci */
6857c2aad20Sopenharmony_cistatic void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
6867c2aad20Sopenharmony_ci{
6877c2aad20Sopenharmony_ci	struct btf_dump_type_aux_state *tstate = &d->type_states[id];
6887c2aad20Sopenharmony_ci	bool top_level_def = cont_id == 0;
6897c2aad20Sopenharmony_ci	const struct btf_type *t;
6907c2aad20Sopenharmony_ci	__u16 kind;
6917c2aad20Sopenharmony_ci
6927c2aad20Sopenharmony_ci	if (tstate->emit_state == EMITTED)
6937c2aad20Sopenharmony_ci		return;
6947c2aad20Sopenharmony_ci
6957c2aad20Sopenharmony_ci	t = btf__type_by_id(d->btf, id);
6967c2aad20Sopenharmony_ci	kind = btf_kind(t);
6977c2aad20Sopenharmony_ci
6987c2aad20Sopenharmony_ci	if (tstate->emit_state == EMITTING) {
6997c2aad20Sopenharmony_ci		if (tstate->fwd_emitted)
7007c2aad20Sopenharmony_ci			return;
7017c2aad20Sopenharmony_ci
7027c2aad20Sopenharmony_ci		switch (kind) {
7037c2aad20Sopenharmony_ci		case BTF_KIND_STRUCT:
7047c2aad20Sopenharmony_ci		case BTF_KIND_UNION:
7057c2aad20Sopenharmony_ci			/*
7067c2aad20Sopenharmony_ci			 * if we are referencing a struct/union that we are
7077c2aad20Sopenharmony_ci			 * part of - then no need for fwd declaration
7087c2aad20Sopenharmony_ci			 */
7097c2aad20Sopenharmony_ci			if (id == cont_id)
7107c2aad20Sopenharmony_ci				return;
7117c2aad20Sopenharmony_ci			if (t->name_off == 0) {
7127c2aad20Sopenharmony_ci				pr_warn("anonymous struct/union loop, id:[%u]\n",
7137c2aad20Sopenharmony_ci					id);
7147c2aad20Sopenharmony_ci				return;
7157c2aad20Sopenharmony_ci			}
7167c2aad20Sopenharmony_ci			btf_dump_emit_struct_fwd(d, id, t);
7177c2aad20Sopenharmony_ci			btf_dump_printf(d, ";\n\n");
7187c2aad20Sopenharmony_ci			tstate->fwd_emitted = 1;
7197c2aad20Sopenharmony_ci			break;
7207c2aad20Sopenharmony_ci		case BTF_KIND_TYPEDEF:
7217c2aad20Sopenharmony_ci			/*
7227c2aad20Sopenharmony_ci			 * for typedef fwd_emitted means typedef definition
7237c2aad20Sopenharmony_ci			 * was emitted, but it can be used only for "weak"
7247c2aad20Sopenharmony_ci			 * references through pointer only, not for embedding
7257c2aad20Sopenharmony_ci			 */
7267c2aad20Sopenharmony_ci			if (!btf_dump_is_blacklisted(d, id)) {
7277c2aad20Sopenharmony_ci				btf_dump_emit_typedef_def(d, id, t, 0);
7287c2aad20Sopenharmony_ci				btf_dump_printf(d, ";\n\n");
7297c2aad20Sopenharmony_ci			}
7307c2aad20Sopenharmony_ci			tstate->fwd_emitted = 1;
7317c2aad20Sopenharmony_ci			break;
7327c2aad20Sopenharmony_ci		default:
7337c2aad20Sopenharmony_ci			break;
7347c2aad20Sopenharmony_ci		}
7357c2aad20Sopenharmony_ci
7367c2aad20Sopenharmony_ci		return;
7377c2aad20Sopenharmony_ci	}
7387c2aad20Sopenharmony_ci
7397c2aad20Sopenharmony_ci	switch (kind) {
7407c2aad20Sopenharmony_ci	case BTF_KIND_INT:
7417c2aad20Sopenharmony_ci		/* Emit type alias definitions if necessary */
7427c2aad20Sopenharmony_ci		btf_dump_emit_missing_aliases(d, id, t);
7437c2aad20Sopenharmony_ci
7447c2aad20Sopenharmony_ci		tstate->emit_state = EMITTED;
7457c2aad20Sopenharmony_ci		break;
7467c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
7477c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
7487c2aad20Sopenharmony_ci		if (top_level_def) {
7497c2aad20Sopenharmony_ci			btf_dump_emit_enum_def(d, id, t, 0);
7507c2aad20Sopenharmony_ci			btf_dump_printf(d, ";\n\n");
7517c2aad20Sopenharmony_ci		}
7527c2aad20Sopenharmony_ci		tstate->emit_state = EMITTED;
7537c2aad20Sopenharmony_ci		break;
7547c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
7557c2aad20Sopenharmony_ci	case BTF_KIND_VOLATILE:
7567c2aad20Sopenharmony_ci	case BTF_KIND_CONST:
7577c2aad20Sopenharmony_ci	case BTF_KIND_RESTRICT:
7587c2aad20Sopenharmony_ci	case BTF_KIND_TYPE_TAG:
7597c2aad20Sopenharmony_ci		btf_dump_emit_type(d, t->type, cont_id);
7607c2aad20Sopenharmony_ci		break;
7617c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
7627c2aad20Sopenharmony_ci		btf_dump_emit_type(d, btf_array(t)->type, cont_id);
7637c2aad20Sopenharmony_ci		break;
7647c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
7657c2aad20Sopenharmony_ci		btf_dump_emit_fwd_def(d, id, t);
7667c2aad20Sopenharmony_ci		btf_dump_printf(d, ";\n\n");
7677c2aad20Sopenharmony_ci		tstate->emit_state = EMITTED;
7687c2aad20Sopenharmony_ci		break;
7697c2aad20Sopenharmony_ci	case BTF_KIND_TYPEDEF:
7707c2aad20Sopenharmony_ci		tstate->emit_state = EMITTING;
7717c2aad20Sopenharmony_ci		btf_dump_emit_type(d, t->type, id);
7727c2aad20Sopenharmony_ci		/*
7737c2aad20Sopenharmony_ci		 * typedef can server as both definition and forward
7747c2aad20Sopenharmony_ci		 * declaration; at this stage someone depends on
7757c2aad20Sopenharmony_ci		 * typedef as a forward declaration (refers to it
7767c2aad20Sopenharmony_ci		 * through pointer), so unless we already did it,
7777c2aad20Sopenharmony_ci		 * emit typedef as a forward declaration
7787c2aad20Sopenharmony_ci		 */
7797c2aad20Sopenharmony_ci		if (!tstate->fwd_emitted && !btf_dump_is_blacklisted(d, id)) {
7807c2aad20Sopenharmony_ci			btf_dump_emit_typedef_def(d, id, t, 0);
7817c2aad20Sopenharmony_ci			btf_dump_printf(d, ";\n\n");
7827c2aad20Sopenharmony_ci		}
7837c2aad20Sopenharmony_ci		tstate->emit_state = EMITTED;
7847c2aad20Sopenharmony_ci		break;
7857c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
7867c2aad20Sopenharmony_ci	case BTF_KIND_UNION:
7877c2aad20Sopenharmony_ci		tstate->emit_state = EMITTING;
7887c2aad20Sopenharmony_ci		/* if it's a top-level struct/union definition or struct/union
7897c2aad20Sopenharmony_ci		 * is anonymous, then in C we'll be emitting all fields and
7907c2aad20Sopenharmony_ci		 * their types (as opposed to just `struct X`), so we need to
7917c2aad20Sopenharmony_ci		 * make sure that all types, referenced from struct/union
7927c2aad20Sopenharmony_ci		 * members have necessary forward-declarations, where
7937c2aad20Sopenharmony_ci		 * applicable
7947c2aad20Sopenharmony_ci		 */
7957c2aad20Sopenharmony_ci		if (top_level_def || t->name_off == 0) {
7967c2aad20Sopenharmony_ci			const struct btf_member *m = btf_members(t);
7977c2aad20Sopenharmony_ci			__u16 vlen = btf_vlen(t);
7987c2aad20Sopenharmony_ci			int i, new_cont_id;
7997c2aad20Sopenharmony_ci
8007c2aad20Sopenharmony_ci			new_cont_id = t->name_off == 0 ? cont_id : id;
8017c2aad20Sopenharmony_ci			for (i = 0; i < vlen; i++, m++)
8027c2aad20Sopenharmony_ci				btf_dump_emit_type(d, m->type, new_cont_id);
8037c2aad20Sopenharmony_ci		} else if (!tstate->fwd_emitted && id != cont_id) {
8047c2aad20Sopenharmony_ci			btf_dump_emit_struct_fwd(d, id, t);
8057c2aad20Sopenharmony_ci			btf_dump_printf(d, ";\n\n");
8067c2aad20Sopenharmony_ci			tstate->fwd_emitted = 1;
8077c2aad20Sopenharmony_ci		}
8087c2aad20Sopenharmony_ci
8097c2aad20Sopenharmony_ci		if (top_level_def) {
8107c2aad20Sopenharmony_ci			btf_dump_emit_struct_def(d, id, t, 0);
8117c2aad20Sopenharmony_ci			btf_dump_printf(d, ";\n\n");
8127c2aad20Sopenharmony_ci			tstate->emit_state = EMITTED;
8137c2aad20Sopenharmony_ci		} else {
8147c2aad20Sopenharmony_ci			tstate->emit_state = NOT_EMITTED;
8157c2aad20Sopenharmony_ci		}
8167c2aad20Sopenharmony_ci		break;
8177c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO: {
8187c2aad20Sopenharmony_ci		const struct btf_param *p = btf_params(t);
8197c2aad20Sopenharmony_ci		__u16 n = btf_vlen(t);
8207c2aad20Sopenharmony_ci		int i;
8217c2aad20Sopenharmony_ci
8227c2aad20Sopenharmony_ci		btf_dump_emit_type(d, t->type, cont_id);
8237c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, p++)
8247c2aad20Sopenharmony_ci			btf_dump_emit_type(d, p->type, cont_id);
8257c2aad20Sopenharmony_ci
8267c2aad20Sopenharmony_ci		break;
8277c2aad20Sopenharmony_ci	}
8287c2aad20Sopenharmony_ci	default:
8297c2aad20Sopenharmony_ci		break;
8307c2aad20Sopenharmony_ci	}
8317c2aad20Sopenharmony_ci}
8327c2aad20Sopenharmony_ci
8337c2aad20Sopenharmony_cistatic bool btf_is_struct_packed(const struct btf *btf, __u32 id,
8347c2aad20Sopenharmony_ci				 const struct btf_type *t)
8357c2aad20Sopenharmony_ci{
8367c2aad20Sopenharmony_ci	const struct btf_member *m;
8377c2aad20Sopenharmony_ci	int max_align = 1, align, i, bit_sz;
8387c2aad20Sopenharmony_ci	__u16 vlen;
8397c2aad20Sopenharmony_ci
8407c2aad20Sopenharmony_ci	m = btf_members(t);
8417c2aad20Sopenharmony_ci	vlen = btf_vlen(t);
8427c2aad20Sopenharmony_ci	/* all non-bitfield fields have to be naturally aligned */
8437c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++, m++) {
8447c2aad20Sopenharmony_ci		align = btf__align_of(btf, m->type);
8457c2aad20Sopenharmony_ci		bit_sz = btf_member_bitfield_size(t, i);
8467c2aad20Sopenharmony_ci		if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
8477c2aad20Sopenharmony_ci			return true;
8487c2aad20Sopenharmony_ci		max_align = max(align, max_align);
8497c2aad20Sopenharmony_ci	}
8507c2aad20Sopenharmony_ci	/* size of a non-packed struct has to be a multiple of its alignment */
8517c2aad20Sopenharmony_ci	if (t->size % max_align != 0)
8527c2aad20Sopenharmony_ci		return true;
8537c2aad20Sopenharmony_ci	/*
8547c2aad20Sopenharmony_ci	 * if original struct was marked as packed, but its layout is
8557c2aad20Sopenharmony_ci	 * naturally aligned, we'll detect that it's not packed
8567c2aad20Sopenharmony_ci	 */
8577c2aad20Sopenharmony_ci	return false;
8587c2aad20Sopenharmony_ci}
8597c2aad20Sopenharmony_ci
8607c2aad20Sopenharmony_cistatic void btf_dump_emit_bit_padding(const struct btf_dump *d,
8617c2aad20Sopenharmony_ci				      int cur_off, int next_off, int next_align,
8627c2aad20Sopenharmony_ci				      bool in_bitfield, int lvl)
8637c2aad20Sopenharmony_ci{
8647c2aad20Sopenharmony_ci	const struct {
8657c2aad20Sopenharmony_ci		const char *name;
8667c2aad20Sopenharmony_ci		int bits;
8677c2aad20Sopenharmony_ci	} pads[] = {
8687c2aad20Sopenharmony_ci		{"long", d->ptr_sz * 8}, {"int", 32}, {"short", 16}, {"char", 8}
8697c2aad20Sopenharmony_ci	};
8707c2aad20Sopenharmony_ci	int new_off, pad_bits, bits, i;
8717c2aad20Sopenharmony_ci	const char *pad_type;
8727c2aad20Sopenharmony_ci
8737c2aad20Sopenharmony_ci	if (cur_off >= next_off)
8747c2aad20Sopenharmony_ci		return; /* no gap */
8757c2aad20Sopenharmony_ci
8767c2aad20Sopenharmony_ci	/* For filling out padding we want to take advantage of
8777c2aad20Sopenharmony_ci	 * natural alignment rules to minimize unnecessary explicit
8787c2aad20Sopenharmony_ci	 * padding. First, we find the largest type (among long, int,
8797c2aad20Sopenharmony_ci	 * short, or char) that can be used to force naturally aligned
8807c2aad20Sopenharmony_ci	 * boundary. Once determined, we'll use such type to fill in
8817c2aad20Sopenharmony_ci	 * the remaining padding gap. In some cases we can rely on
8827c2aad20Sopenharmony_ci	 * compiler filling some gaps, but sometimes we need to force
8837c2aad20Sopenharmony_ci	 * alignment to close natural alignment with markers like
8847c2aad20Sopenharmony_ci	 * `long: 0` (this is always the case for bitfields).  Note
8857c2aad20Sopenharmony_ci	 * that even if struct itself has, let's say 4-byte alignment
8867c2aad20Sopenharmony_ci	 * (i.e., it only uses up to int-aligned types), using `long:
8877c2aad20Sopenharmony_ci	 * X;` explicit padding doesn't actually change struct's
8887c2aad20Sopenharmony_ci	 * overall alignment requirements, but compiler does take into
8897c2aad20Sopenharmony_ci	 * account that type's (long, in this example) natural
8907c2aad20Sopenharmony_ci	 * alignment requirements when adding implicit padding. We use
8917c2aad20Sopenharmony_ci	 * this fact heavily and don't worry about ruining correct
8927c2aad20Sopenharmony_ci	 * struct alignment requirement.
8937c2aad20Sopenharmony_ci	 */
8947c2aad20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pads); i++) {
8957c2aad20Sopenharmony_ci		pad_bits = pads[i].bits;
8967c2aad20Sopenharmony_ci		pad_type = pads[i].name;
8977c2aad20Sopenharmony_ci
8987c2aad20Sopenharmony_ci		new_off = roundup(cur_off, pad_bits);
8997c2aad20Sopenharmony_ci		if (new_off <= next_off)
9007c2aad20Sopenharmony_ci			break;
9017c2aad20Sopenharmony_ci	}
9027c2aad20Sopenharmony_ci
9037c2aad20Sopenharmony_ci	if (new_off > cur_off && new_off <= next_off) {
9047c2aad20Sopenharmony_ci		/* We need explicit `<type>: 0` aligning mark if next
9057c2aad20Sopenharmony_ci		 * field is right on alignment offset and its
9067c2aad20Sopenharmony_ci		 * alignment requirement is less strict than <type>'s
9077c2aad20Sopenharmony_ci		 * alignment (so compiler won't naturally align to the
9087c2aad20Sopenharmony_ci		 * offset we expect), or if subsequent `<type>: X`,
9097c2aad20Sopenharmony_ci		 * will actually completely fit in the remaining hole,
9107c2aad20Sopenharmony_ci		 * making compiler basically ignore `<type>: X`
9117c2aad20Sopenharmony_ci		 * completely.
9127c2aad20Sopenharmony_ci		 */
9137c2aad20Sopenharmony_ci		if (in_bitfield ||
9147c2aad20Sopenharmony_ci		    (new_off == next_off && roundup(cur_off, next_align * 8) != new_off) ||
9157c2aad20Sopenharmony_ci		    (new_off != next_off && next_off - new_off <= new_off - cur_off))
9167c2aad20Sopenharmony_ci			/* but for bitfields we'll emit explicit bit count */
9177c2aad20Sopenharmony_ci			btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type,
9187c2aad20Sopenharmony_ci					in_bitfield ? new_off - cur_off : 0);
9197c2aad20Sopenharmony_ci		cur_off = new_off;
9207c2aad20Sopenharmony_ci	}
9217c2aad20Sopenharmony_ci
9227c2aad20Sopenharmony_ci	/* Now we know we start at naturally aligned offset for a chosen
9237c2aad20Sopenharmony_ci	 * padding type (long, int, short, or char), and so the rest is just
9247c2aad20Sopenharmony_ci	 * a straightforward filling of remaining padding gap with full
9257c2aad20Sopenharmony_ci	 * `<type>: sizeof(<type>);` markers, except for the last one, which
9267c2aad20Sopenharmony_ci	 * might need smaller than sizeof(<type>) padding.
9277c2aad20Sopenharmony_ci	 */
9287c2aad20Sopenharmony_ci	while (cur_off != next_off) {
9297c2aad20Sopenharmony_ci		bits = min(next_off - cur_off, pad_bits);
9307c2aad20Sopenharmony_ci		if (bits == pad_bits) {
9317c2aad20Sopenharmony_ci			btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
9327c2aad20Sopenharmony_ci			cur_off += bits;
9337c2aad20Sopenharmony_ci			continue;
9347c2aad20Sopenharmony_ci		}
9357c2aad20Sopenharmony_ci		/* For the remainder padding that doesn't cover entire
9367c2aad20Sopenharmony_ci		 * pad_type bit length, we pick the smallest necessary type.
9377c2aad20Sopenharmony_ci		 * This is pure aesthetics, we could have just used `long`,
9387c2aad20Sopenharmony_ci		 * but having smallest necessary one communicates better the
9397c2aad20Sopenharmony_ci		 * scale of the padding gap.
9407c2aad20Sopenharmony_ci		 */
9417c2aad20Sopenharmony_ci		for (i = ARRAY_SIZE(pads) - 1; i >= 0; i--) {
9427c2aad20Sopenharmony_ci			pad_type = pads[i].name;
9437c2aad20Sopenharmony_ci			pad_bits = pads[i].bits;
9447c2aad20Sopenharmony_ci			if (pad_bits < bits)
9457c2aad20Sopenharmony_ci				continue;
9467c2aad20Sopenharmony_ci
9477c2aad20Sopenharmony_ci			btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, bits);
9487c2aad20Sopenharmony_ci			cur_off += bits;
9497c2aad20Sopenharmony_ci			break;
9507c2aad20Sopenharmony_ci		}
9517c2aad20Sopenharmony_ci	}
9527c2aad20Sopenharmony_ci}
9537c2aad20Sopenharmony_ci
9547c2aad20Sopenharmony_cistatic void btf_dump_emit_struct_fwd(struct btf_dump *d, __u32 id,
9557c2aad20Sopenharmony_ci				     const struct btf_type *t)
9567c2aad20Sopenharmony_ci{
9577c2aad20Sopenharmony_ci	btf_dump_printf(d, "%s%s%s",
9587c2aad20Sopenharmony_ci			btf_is_struct(t) ? "struct" : "union",
9597c2aad20Sopenharmony_ci			t->name_off ? " " : "",
9607c2aad20Sopenharmony_ci			btf_dump_type_name(d, id));
9617c2aad20Sopenharmony_ci}
9627c2aad20Sopenharmony_ci
9637c2aad20Sopenharmony_cistatic void btf_dump_emit_struct_def(struct btf_dump *d,
9647c2aad20Sopenharmony_ci				     __u32 id,
9657c2aad20Sopenharmony_ci				     const struct btf_type *t,
9667c2aad20Sopenharmony_ci				     int lvl)
9677c2aad20Sopenharmony_ci{
9687c2aad20Sopenharmony_ci	const struct btf_member *m = btf_members(t);
9697c2aad20Sopenharmony_ci	bool is_struct = btf_is_struct(t);
9707c2aad20Sopenharmony_ci	bool packed, prev_bitfield = false;
9717c2aad20Sopenharmony_ci	int align, i, off = 0;
9727c2aad20Sopenharmony_ci	__u16 vlen = btf_vlen(t);
9737c2aad20Sopenharmony_ci
9747c2aad20Sopenharmony_ci	align = btf__align_of(d->btf, id);
9757c2aad20Sopenharmony_ci	packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
9767c2aad20Sopenharmony_ci
9777c2aad20Sopenharmony_ci	btf_dump_printf(d, "%s%s%s {",
9787c2aad20Sopenharmony_ci			is_struct ? "struct" : "union",
9797c2aad20Sopenharmony_ci			t->name_off ? " " : "",
9807c2aad20Sopenharmony_ci			btf_dump_type_name(d, id));
9817c2aad20Sopenharmony_ci
9827c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++, m++) {
9837c2aad20Sopenharmony_ci		const char *fname;
9847c2aad20Sopenharmony_ci		int m_off, m_sz, m_align;
9857c2aad20Sopenharmony_ci		bool in_bitfield;
9867c2aad20Sopenharmony_ci
9877c2aad20Sopenharmony_ci		fname = btf_name_of(d, m->name_off);
9887c2aad20Sopenharmony_ci		m_sz = btf_member_bitfield_size(t, i);
9897c2aad20Sopenharmony_ci		m_off = btf_member_bit_offset(t, i);
9907c2aad20Sopenharmony_ci		m_align = packed ? 1 : btf__align_of(d->btf, m->type);
9917c2aad20Sopenharmony_ci
9927c2aad20Sopenharmony_ci		in_bitfield = prev_bitfield && m_sz != 0;
9937c2aad20Sopenharmony_ci
9947c2aad20Sopenharmony_ci		btf_dump_emit_bit_padding(d, off, m_off, m_align, in_bitfield, lvl + 1);
9957c2aad20Sopenharmony_ci		btf_dump_printf(d, "\n%s", pfx(lvl + 1));
9967c2aad20Sopenharmony_ci		btf_dump_emit_type_decl(d, m->type, fname, lvl + 1);
9977c2aad20Sopenharmony_ci
9987c2aad20Sopenharmony_ci		if (m_sz) {
9997c2aad20Sopenharmony_ci			btf_dump_printf(d, ": %d", m_sz);
10007c2aad20Sopenharmony_ci			off = m_off + m_sz;
10017c2aad20Sopenharmony_ci			prev_bitfield = true;
10027c2aad20Sopenharmony_ci		} else {
10037c2aad20Sopenharmony_ci			m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
10047c2aad20Sopenharmony_ci			off = m_off + m_sz * 8;
10057c2aad20Sopenharmony_ci			prev_bitfield = false;
10067c2aad20Sopenharmony_ci		}
10077c2aad20Sopenharmony_ci
10087c2aad20Sopenharmony_ci		btf_dump_printf(d, ";");
10097c2aad20Sopenharmony_ci	}
10107c2aad20Sopenharmony_ci
10117c2aad20Sopenharmony_ci	/* pad at the end, if necessary */
10127c2aad20Sopenharmony_ci	if (is_struct)
10137c2aad20Sopenharmony_ci		btf_dump_emit_bit_padding(d, off, t->size * 8, align, false, lvl + 1);
10147c2aad20Sopenharmony_ci
10157c2aad20Sopenharmony_ci	/*
10167c2aad20Sopenharmony_ci	 * Keep `struct empty {}` on a single line,
10177c2aad20Sopenharmony_ci	 * only print newline when there are regular or padding fields.
10187c2aad20Sopenharmony_ci	 */
10197c2aad20Sopenharmony_ci	if (vlen || t->size) {
10207c2aad20Sopenharmony_ci		btf_dump_printf(d, "\n");
10217c2aad20Sopenharmony_ci		btf_dump_printf(d, "%s}", pfx(lvl));
10227c2aad20Sopenharmony_ci	} else {
10237c2aad20Sopenharmony_ci		btf_dump_printf(d, "}");
10247c2aad20Sopenharmony_ci	}
10257c2aad20Sopenharmony_ci	if (packed)
10267c2aad20Sopenharmony_ci		btf_dump_printf(d, " __attribute__((packed))");
10277c2aad20Sopenharmony_ci}
10287c2aad20Sopenharmony_ci
10297c2aad20Sopenharmony_cistatic const char *missing_base_types[][2] = {
10307c2aad20Sopenharmony_ci	/*
10317c2aad20Sopenharmony_ci	 * GCC emits typedefs to its internal __PolyX_t types when compiling Arm
10327c2aad20Sopenharmony_ci	 * SIMD intrinsics. Alias them to standard base types.
10337c2aad20Sopenharmony_ci	 */
10347c2aad20Sopenharmony_ci	{ "__Poly8_t",		"unsigned char" },
10357c2aad20Sopenharmony_ci	{ "__Poly16_t",		"unsigned short" },
10367c2aad20Sopenharmony_ci	{ "__Poly64_t",		"unsigned long long" },
10377c2aad20Sopenharmony_ci	{ "__Poly128_t",	"unsigned __int128" },
10387c2aad20Sopenharmony_ci};
10397c2aad20Sopenharmony_ci
10407c2aad20Sopenharmony_cistatic void btf_dump_emit_missing_aliases(struct btf_dump *d, __u32 id,
10417c2aad20Sopenharmony_ci					  const struct btf_type *t)
10427c2aad20Sopenharmony_ci{
10437c2aad20Sopenharmony_ci	const char *name = btf_dump_type_name(d, id);
10447c2aad20Sopenharmony_ci	int i;
10457c2aad20Sopenharmony_ci
10467c2aad20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(missing_base_types); i++) {
10477c2aad20Sopenharmony_ci		if (strcmp(name, missing_base_types[i][0]) == 0) {
10487c2aad20Sopenharmony_ci			btf_dump_printf(d, "typedef %s %s;\n\n",
10497c2aad20Sopenharmony_ci					missing_base_types[i][1], name);
10507c2aad20Sopenharmony_ci			break;
10517c2aad20Sopenharmony_ci		}
10527c2aad20Sopenharmony_ci	}
10537c2aad20Sopenharmony_ci}
10547c2aad20Sopenharmony_ci
10557c2aad20Sopenharmony_cistatic void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
10567c2aad20Sopenharmony_ci				   const struct btf_type *t)
10577c2aad20Sopenharmony_ci{
10587c2aad20Sopenharmony_ci	btf_dump_printf(d, "enum %s", btf_dump_type_name(d, id));
10597c2aad20Sopenharmony_ci}
10607c2aad20Sopenharmony_ci
10617c2aad20Sopenharmony_cistatic void btf_dump_emit_enum32_val(struct btf_dump *d,
10627c2aad20Sopenharmony_ci				     const struct btf_type *t,
10637c2aad20Sopenharmony_ci				     int lvl, __u16 vlen)
10647c2aad20Sopenharmony_ci{
10657c2aad20Sopenharmony_ci	const struct btf_enum *v = btf_enum(t);
10667c2aad20Sopenharmony_ci	bool is_signed = btf_kflag(t);
10677c2aad20Sopenharmony_ci	const char *fmt_str;
10687c2aad20Sopenharmony_ci	const char *name;
10697c2aad20Sopenharmony_ci	size_t dup_cnt;
10707c2aad20Sopenharmony_ci	int i;
10717c2aad20Sopenharmony_ci
10727c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++, v++) {
10737c2aad20Sopenharmony_ci		name = btf_name_of(d, v->name_off);
10747c2aad20Sopenharmony_ci		/* enumerators share namespace with typedef idents */
10757c2aad20Sopenharmony_ci		dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
10767c2aad20Sopenharmony_ci		if (dup_cnt > 1) {
10777c2aad20Sopenharmony_ci			fmt_str = is_signed ? "\n%s%s___%zd = %d," : "\n%s%s___%zd = %u,";
10787c2aad20Sopenharmony_ci			btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, dup_cnt, v->val);
10797c2aad20Sopenharmony_ci		} else {
10807c2aad20Sopenharmony_ci			fmt_str = is_signed ? "\n%s%s = %d," : "\n%s%s = %u,";
10817c2aad20Sopenharmony_ci			btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, v->val);
10827c2aad20Sopenharmony_ci		}
10837c2aad20Sopenharmony_ci	}
10847c2aad20Sopenharmony_ci}
10857c2aad20Sopenharmony_ci
10867c2aad20Sopenharmony_cistatic void btf_dump_emit_enum64_val(struct btf_dump *d,
10877c2aad20Sopenharmony_ci				     const struct btf_type *t,
10887c2aad20Sopenharmony_ci				     int lvl, __u16 vlen)
10897c2aad20Sopenharmony_ci{
10907c2aad20Sopenharmony_ci	const struct btf_enum64 *v = btf_enum64(t);
10917c2aad20Sopenharmony_ci	bool is_signed = btf_kflag(t);
10927c2aad20Sopenharmony_ci	const char *fmt_str;
10937c2aad20Sopenharmony_ci	const char *name;
10947c2aad20Sopenharmony_ci	size_t dup_cnt;
10957c2aad20Sopenharmony_ci	__u64 val;
10967c2aad20Sopenharmony_ci	int i;
10977c2aad20Sopenharmony_ci
10987c2aad20Sopenharmony_ci	for (i = 0; i < vlen; i++, v++) {
10997c2aad20Sopenharmony_ci		name = btf_name_of(d, v->name_off);
11007c2aad20Sopenharmony_ci		dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
11017c2aad20Sopenharmony_ci		val = btf_enum64_value(v);
11027c2aad20Sopenharmony_ci		if (dup_cnt > 1) {
11037c2aad20Sopenharmony_ci			fmt_str = is_signed ? "\n%s%s___%zd = %lldLL,"
11047c2aad20Sopenharmony_ci					    : "\n%s%s___%zd = %lluULL,";
11057c2aad20Sopenharmony_ci			btf_dump_printf(d, fmt_str,
11067c2aad20Sopenharmony_ci					pfx(lvl + 1), name, dup_cnt,
11077c2aad20Sopenharmony_ci					(unsigned long long)val);
11087c2aad20Sopenharmony_ci		} else {
11097c2aad20Sopenharmony_ci			fmt_str = is_signed ? "\n%s%s = %lldLL,"
11107c2aad20Sopenharmony_ci					    : "\n%s%s = %lluULL,";
11117c2aad20Sopenharmony_ci			btf_dump_printf(d, fmt_str,
11127c2aad20Sopenharmony_ci					pfx(lvl + 1), name,
11137c2aad20Sopenharmony_ci					(unsigned long long)val);
11147c2aad20Sopenharmony_ci		}
11157c2aad20Sopenharmony_ci	}
11167c2aad20Sopenharmony_ci}
11177c2aad20Sopenharmony_cistatic void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
11187c2aad20Sopenharmony_ci				   const struct btf_type *t,
11197c2aad20Sopenharmony_ci				   int lvl)
11207c2aad20Sopenharmony_ci{
11217c2aad20Sopenharmony_ci	__u16 vlen = btf_vlen(t);
11227c2aad20Sopenharmony_ci
11237c2aad20Sopenharmony_ci	btf_dump_printf(d, "enum%s%s",
11247c2aad20Sopenharmony_ci			t->name_off ? " " : "",
11257c2aad20Sopenharmony_ci			btf_dump_type_name(d, id));
11267c2aad20Sopenharmony_ci
11277c2aad20Sopenharmony_ci	if (!vlen)
11287c2aad20Sopenharmony_ci		return;
11297c2aad20Sopenharmony_ci
11307c2aad20Sopenharmony_ci	btf_dump_printf(d, " {");
11317c2aad20Sopenharmony_ci	if (btf_is_enum(t))
11327c2aad20Sopenharmony_ci		btf_dump_emit_enum32_val(d, t, lvl, vlen);
11337c2aad20Sopenharmony_ci	else
11347c2aad20Sopenharmony_ci		btf_dump_emit_enum64_val(d, t, lvl, vlen);
11357c2aad20Sopenharmony_ci	btf_dump_printf(d, "\n%s}", pfx(lvl));
11367c2aad20Sopenharmony_ci
11377c2aad20Sopenharmony_ci	/* special case enums with special sizes */
11387c2aad20Sopenharmony_ci	if (t->size == 1) {
11397c2aad20Sopenharmony_ci		/* one-byte enums can be forced with mode(byte) attribute */
11407c2aad20Sopenharmony_ci		btf_dump_printf(d, " __attribute__((mode(byte)))");
11417c2aad20Sopenharmony_ci	} else if (t->size == 8 && d->ptr_sz == 8) {
11427c2aad20Sopenharmony_ci		/* enum can be 8-byte sized if one of the enumerator values
11437c2aad20Sopenharmony_ci		 * doesn't fit in 32-bit integer, or by adding mode(word)
11447c2aad20Sopenharmony_ci		 * attribute (but probably only on 64-bit architectures); do
11457c2aad20Sopenharmony_ci		 * our best here to try to satisfy the contract without adding
11467c2aad20Sopenharmony_ci		 * unnecessary attributes
11477c2aad20Sopenharmony_ci		 */
11487c2aad20Sopenharmony_ci		bool needs_word_mode;
11497c2aad20Sopenharmony_ci
11507c2aad20Sopenharmony_ci		if (btf_is_enum(t)) {
11517c2aad20Sopenharmony_ci			/* enum can't represent 64-bit values, so we need word mode */
11527c2aad20Sopenharmony_ci			needs_word_mode = true;
11537c2aad20Sopenharmony_ci		} else {
11547c2aad20Sopenharmony_ci			/* enum64 needs mode(word) if none of its values has
11557c2aad20Sopenharmony_ci			 * non-zero upper 32-bits (which means that all values
11567c2aad20Sopenharmony_ci			 * fit in 32-bit integers and won't cause compiler to
11577c2aad20Sopenharmony_ci			 * bump enum to be 64-bit naturally
11587c2aad20Sopenharmony_ci			 */
11597c2aad20Sopenharmony_ci			int i;
11607c2aad20Sopenharmony_ci
11617c2aad20Sopenharmony_ci			needs_word_mode = true;
11627c2aad20Sopenharmony_ci			for (i = 0; i < vlen; i++) {
11637c2aad20Sopenharmony_ci				if (btf_enum64(t)[i].val_hi32 != 0) {
11647c2aad20Sopenharmony_ci					needs_word_mode = false;
11657c2aad20Sopenharmony_ci					break;
11667c2aad20Sopenharmony_ci				}
11677c2aad20Sopenharmony_ci			}
11687c2aad20Sopenharmony_ci		}
11697c2aad20Sopenharmony_ci		if (needs_word_mode)
11707c2aad20Sopenharmony_ci			btf_dump_printf(d, " __attribute__((mode(word)))");
11717c2aad20Sopenharmony_ci	}
11727c2aad20Sopenharmony_ci
11737c2aad20Sopenharmony_ci}
11747c2aad20Sopenharmony_ci
11757c2aad20Sopenharmony_cistatic void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
11767c2aad20Sopenharmony_ci				  const struct btf_type *t)
11777c2aad20Sopenharmony_ci{
11787c2aad20Sopenharmony_ci	const char *name = btf_dump_type_name(d, id);
11797c2aad20Sopenharmony_ci
11807c2aad20Sopenharmony_ci	if (btf_kflag(t))
11817c2aad20Sopenharmony_ci		btf_dump_printf(d, "union %s", name);
11827c2aad20Sopenharmony_ci	else
11837c2aad20Sopenharmony_ci		btf_dump_printf(d, "struct %s", name);
11847c2aad20Sopenharmony_ci}
11857c2aad20Sopenharmony_ci
11867c2aad20Sopenharmony_cistatic void btf_dump_emit_typedef_def(struct btf_dump *d, __u32 id,
11877c2aad20Sopenharmony_ci				     const struct btf_type *t, int lvl)
11887c2aad20Sopenharmony_ci{
11897c2aad20Sopenharmony_ci	const char *name = btf_dump_ident_name(d, id);
11907c2aad20Sopenharmony_ci
11917c2aad20Sopenharmony_ci	/*
11927c2aad20Sopenharmony_ci	 * Old GCC versions are emitting invalid typedef for __gnuc_va_list
11937c2aad20Sopenharmony_ci	 * pointing to VOID. This generates warnings from btf_dump() and
11947c2aad20Sopenharmony_ci	 * results in uncompilable header file, so we are fixing it up here
11957c2aad20Sopenharmony_ci	 * with valid typedef into __builtin_va_list.
11967c2aad20Sopenharmony_ci	 */
11977c2aad20Sopenharmony_ci	if (t->type == 0 && strcmp(name, "__gnuc_va_list") == 0) {
11987c2aad20Sopenharmony_ci		btf_dump_printf(d, "typedef __builtin_va_list __gnuc_va_list");
11997c2aad20Sopenharmony_ci		return;
12007c2aad20Sopenharmony_ci	}
12017c2aad20Sopenharmony_ci
12027c2aad20Sopenharmony_ci	btf_dump_printf(d, "typedef ");
12037c2aad20Sopenharmony_ci	btf_dump_emit_type_decl(d, t->type, name, lvl);
12047c2aad20Sopenharmony_ci}
12057c2aad20Sopenharmony_ci
12067c2aad20Sopenharmony_cistatic int btf_dump_push_decl_stack_id(struct btf_dump *d, __u32 id)
12077c2aad20Sopenharmony_ci{
12087c2aad20Sopenharmony_ci	__u32 *new_stack;
12097c2aad20Sopenharmony_ci	size_t new_cap;
12107c2aad20Sopenharmony_ci
12117c2aad20Sopenharmony_ci	if (d->decl_stack_cnt >= d->decl_stack_cap) {
12127c2aad20Sopenharmony_ci		new_cap = max(16, d->decl_stack_cap * 3 / 2);
12137c2aad20Sopenharmony_ci		new_stack = libbpf_reallocarray(d->decl_stack, new_cap, sizeof(new_stack[0]));
12147c2aad20Sopenharmony_ci		if (!new_stack)
12157c2aad20Sopenharmony_ci			return -ENOMEM;
12167c2aad20Sopenharmony_ci		d->decl_stack = new_stack;
12177c2aad20Sopenharmony_ci		d->decl_stack_cap = new_cap;
12187c2aad20Sopenharmony_ci	}
12197c2aad20Sopenharmony_ci
12207c2aad20Sopenharmony_ci	d->decl_stack[d->decl_stack_cnt++] = id;
12217c2aad20Sopenharmony_ci
12227c2aad20Sopenharmony_ci	return 0;
12237c2aad20Sopenharmony_ci}
12247c2aad20Sopenharmony_ci
12257c2aad20Sopenharmony_ci/*
12267c2aad20Sopenharmony_ci * Emit type declaration (e.g., field type declaration in a struct or argument
12277c2aad20Sopenharmony_ci * declaration in function prototype) in correct C syntax.
12287c2aad20Sopenharmony_ci *
12297c2aad20Sopenharmony_ci * For most types it's trivial, but there are few quirky type declaration
12307c2aad20Sopenharmony_ci * cases worth mentioning:
12317c2aad20Sopenharmony_ci *   - function prototypes (especially nesting of function prototypes);
12327c2aad20Sopenharmony_ci *   - arrays;
12337c2aad20Sopenharmony_ci *   - const/volatile/restrict for pointers vs other types.
12347c2aad20Sopenharmony_ci *
12357c2aad20Sopenharmony_ci * For a good discussion of *PARSING* C syntax (as a human), see
12367c2aad20Sopenharmony_ci * Peter van der Linden's "Expert C Programming: Deep C Secrets",
12377c2aad20Sopenharmony_ci * Ch.3 "Unscrambling Declarations in C".
12387c2aad20Sopenharmony_ci *
12397c2aad20Sopenharmony_ci * It won't help with BTF to C conversion much, though, as it's an opposite
12407c2aad20Sopenharmony_ci * problem. So we came up with this algorithm in reverse to van der Linden's
12417c2aad20Sopenharmony_ci * parsing algorithm. It goes from structured BTF representation of type
12427c2aad20Sopenharmony_ci * declaration to a valid compilable C syntax.
12437c2aad20Sopenharmony_ci *
12447c2aad20Sopenharmony_ci * For instance, consider this C typedef:
12457c2aad20Sopenharmony_ci *	typedef const int * const * arr[10] arr_t;
12467c2aad20Sopenharmony_ci * It will be represented in BTF with this chain of BTF types:
12477c2aad20Sopenharmony_ci *	[typedef] -> [array] -> [ptr] -> [const] -> [ptr] -> [const] -> [int]
12487c2aad20Sopenharmony_ci *
12497c2aad20Sopenharmony_ci * Notice how [const] modifier always goes before type it modifies in BTF type
12507c2aad20Sopenharmony_ci * graph, but in C syntax, const/volatile/restrict modifiers are written to
12517c2aad20Sopenharmony_ci * the right of pointers, but to the left of other types. There are also other
12527c2aad20Sopenharmony_ci * quirks, like function pointers, arrays of them, functions returning other
12537c2aad20Sopenharmony_ci * functions, etc.
12547c2aad20Sopenharmony_ci *
12557c2aad20Sopenharmony_ci * We handle that by pushing all the types to a stack, until we hit "terminal"
12567c2aad20Sopenharmony_ci * type (int/enum/struct/union/fwd). Then depending on the kind of a type on
12577c2aad20Sopenharmony_ci * top of a stack, modifiers are handled differently. Array/function pointers
12587c2aad20Sopenharmony_ci * have also wildly different syntax and how nesting of them are done. See
12597c2aad20Sopenharmony_ci * code for authoritative definition.
12607c2aad20Sopenharmony_ci *
12617c2aad20Sopenharmony_ci * To avoid allocating new stack for each independent chain of BTF types, we
12627c2aad20Sopenharmony_ci * share one bigger stack, with each chain working only on its own local view
12637c2aad20Sopenharmony_ci * of a stack frame. Some care is required to "pop" stack frames after
12647c2aad20Sopenharmony_ci * processing type declaration chain.
12657c2aad20Sopenharmony_ci */
12667c2aad20Sopenharmony_ciint btf_dump__emit_type_decl(struct btf_dump *d, __u32 id,
12677c2aad20Sopenharmony_ci			     const struct btf_dump_emit_type_decl_opts *opts)
12687c2aad20Sopenharmony_ci{
12697c2aad20Sopenharmony_ci	const char *fname;
12707c2aad20Sopenharmony_ci	int lvl, err;
12717c2aad20Sopenharmony_ci
12727c2aad20Sopenharmony_ci	if (!OPTS_VALID(opts, btf_dump_emit_type_decl_opts))
12737c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
12747c2aad20Sopenharmony_ci
12757c2aad20Sopenharmony_ci	err = btf_dump_resize(d);
12767c2aad20Sopenharmony_ci	if (err)
12777c2aad20Sopenharmony_ci		return libbpf_err(err);
12787c2aad20Sopenharmony_ci
12797c2aad20Sopenharmony_ci	fname = OPTS_GET(opts, field_name, "");
12807c2aad20Sopenharmony_ci	lvl = OPTS_GET(opts, indent_level, 0);
12817c2aad20Sopenharmony_ci	d->strip_mods = OPTS_GET(opts, strip_mods, false);
12827c2aad20Sopenharmony_ci	btf_dump_emit_type_decl(d, id, fname, lvl);
12837c2aad20Sopenharmony_ci	d->strip_mods = false;
12847c2aad20Sopenharmony_ci	return 0;
12857c2aad20Sopenharmony_ci}
12867c2aad20Sopenharmony_ci
12877c2aad20Sopenharmony_cistatic void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id,
12887c2aad20Sopenharmony_ci				    const char *fname, int lvl)
12897c2aad20Sopenharmony_ci{
12907c2aad20Sopenharmony_ci	struct id_stack decl_stack;
12917c2aad20Sopenharmony_ci	const struct btf_type *t;
12927c2aad20Sopenharmony_ci	int err, stack_start;
12937c2aad20Sopenharmony_ci
12947c2aad20Sopenharmony_ci	stack_start = d->decl_stack_cnt;
12957c2aad20Sopenharmony_ci	for (;;) {
12967c2aad20Sopenharmony_ci		t = btf__type_by_id(d->btf, id);
12977c2aad20Sopenharmony_ci		if (d->strip_mods && btf_is_mod(t))
12987c2aad20Sopenharmony_ci			goto skip_mod;
12997c2aad20Sopenharmony_ci
13007c2aad20Sopenharmony_ci		err = btf_dump_push_decl_stack_id(d, id);
13017c2aad20Sopenharmony_ci		if (err < 0) {
13027c2aad20Sopenharmony_ci			/*
13037c2aad20Sopenharmony_ci			 * if we don't have enough memory for entire type decl
13047c2aad20Sopenharmony_ci			 * chain, restore stack, emit warning, and try to
13057c2aad20Sopenharmony_ci			 * proceed nevertheless
13067c2aad20Sopenharmony_ci			 */
13077c2aad20Sopenharmony_ci			pr_warn("not enough memory for decl stack:%d", err);
13087c2aad20Sopenharmony_ci			d->decl_stack_cnt = stack_start;
13097c2aad20Sopenharmony_ci			return;
13107c2aad20Sopenharmony_ci		}
13117c2aad20Sopenharmony_ciskip_mod:
13127c2aad20Sopenharmony_ci		/* VOID */
13137c2aad20Sopenharmony_ci		if (id == 0)
13147c2aad20Sopenharmony_ci			break;
13157c2aad20Sopenharmony_ci
13167c2aad20Sopenharmony_ci		switch (btf_kind(t)) {
13177c2aad20Sopenharmony_ci		case BTF_KIND_PTR:
13187c2aad20Sopenharmony_ci		case BTF_KIND_VOLATILE:
13197c2aad20Sopenharmony_ci		case BTF_KIND_CONST:
13207c2aad20Sopenharmony_ci		case BTF_KIND_RESTRICT:
13217c2aad20Sopenharmony_ci		case BTF_KIND_FUNC_PROTO:
13227c2aad20Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
13237c2aad20Sopenharmony_ci			id = t->type;
13247c2aad20Sopenharmony_ci			break;
13257c2aad20Sopenharmony_ci		case BTF_KIND_ARRAY:
13267c2aad20Sopenharmony_ci			id = btf_array(t)->type;
13277c2aad20Sopenharmony_ci			break;
13287c2aad20Sopenharmony_ci		case BTF_KIND_INT:
13297c2aad20Sopenharmony_ci		case BTF_KIND_ENUM:
13307c2aad20Sopenharmony_ci		case BTF_KIND_ENUM64:
13317c2aad20Sopenharmony_ci		case BTF_KIND_FWD:
13327c2aad20Sopenharmony_ci		case BTF_KIND_STRUCT:
13337c2aad20Sopenharmony_ci		case BTF_KIND_UNION:
13347c2aad20Sopenharmony_ci		case BTF_KIND_TYPEDEF:
13357c2aad20Sopenharmony_ci		case BTF_KIND_FLOAT:
13367c2aad20Sopenharmony_ci			goto done;
13377c2aad20Sopenharmony_ci		default:
13387c2aad20Sopenharmony_ci			pr_warn("unexpected type in decl chain, kind:%u, id:[%u]\n",
13397c2aad20Sopenharmony_ci				btf_kind(t), id);
13407c2aad20Sopenharmony_ci			goto done;
13417c2aad20Sopenharmony_ci		}
13427c2aad20Sopenharmony_ci	}
13437c2aad20Sopenharmony_cidone:
13447c2aad20Sopenharmony_ci	/*
13457c2aad20Sopenharmony_ci	 * We might be inside a chain of declarations (e.g., array of function
13467c2aad20Sopenharmony_ci	 * pointers returning anonymous (so inlined) structs, having another
13477c2aad20Sopenharmony_ci	 * array field). Each of those needs its own "stack frame" to handle
13487c2aad20Sopenharmony_ci	 * emitting of declarations. Those stack frames are non-overlapping
13497c2aad20Sopenharmony_ci	 * portions of shared btf_dump->decl_stack. To make it a bit nicer to
13507c2aad20Sopenharmony_ci	 * handle this set of nested stacks, we create a view corresponding to
13517c2aad20Sopenharmony_ci	 * our own "stack frame" and work with it as an independent stack.
13527c2aad20Sopenharmony_ci	 * We'll need to clean up after emit_type_chain() returns, though.
13537c2aad20Sopenharmony_ci	 */
13547c2aad20Sopenharmony_ci	decl_stack.ids = d->decl_stack + stack_start;
13557c2aad20Sopenharmony_ci	decl_stack.cnt = d->decl_stack_cnt - stack_start;
13567c2aad20Sopenharmony_ci	btf_dump_emit_type_chain(d, &decl_stack, fname, lvl);
13577c2aad20Sopenharmony_ci	/*
13587c2aad20Sopenharmony_ci	 * emit_type_chain() guarantees that it will pop its entire decl_stack
13597c2aad20Sopenharmony_ci	 * frame before returning. But it works with a read-only view into
13607c2aad20Sopenharmony_ci	 * decl_stack, so it doesn't actually pop anything from the
13617c2aad20Sopenharmony_ci	 * perspective of shared btf_dump->decl_stack, per se. We need to
13627c2aad20Sopenharmony_ci	 * reset decl_stack state to how it was before us to avoid it growing
13637c2aad20Sopenharmony_ci	 * all the time.
13647c2aad20Sopenharmony_ci	 */
13657c2aad20Sopenharmony_ci	d->decl_stack_cnt = stack_start;
13667c2aad20Sopenharmony_ci}
13677c2aad20Sopenharmony_ci
13687c2aad20Sopenharmony_cistatic void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
13697c2aad20Sopenharmony_ci{
13707c2aad20Sopenharmony_ci	const struct btf_type *t;
13717c2aad20Sopenharmony_ci	__u32 id;
13727c2aad20Sopenharmony_ci
13737c2aad20Sopenharmony_ci	while (decl_stack->cnt) {
13747c2aad20Sopenharmony_ci		id = decl_stack->ids[decl_stack->cnt - 1];
13757c2aad20Sopenharmony_ci		t = btf__type_by_id(d->btf, id);
13767c2aad20Sopenharmony_ci
13777c2aad20Sopenharmony_ci		switch (btf_kind(t)) {
13787c2aad20Sopenharmony_ci		case BTF_KIND_VOLATILE:
13797c2aad20Sopenharmony_ci			btf_dump_printf(d, "volatile ");
13807c2aad20Sopenharmony_ci			break;
13817c2aad20Sopenharmony_ci		case BTF_KIND_CONST:
13827c2aad20Sopenharmony_ci			btf_dump_printf(d, "const ");
13837c2aad20Sopenharmony_ci			break;
13847c2aad20Sopenharmony_ci		case BTF_KIND_RESTRICT:
13857c2aad20Sopenharmony_ci			btf_dump_printf(d, "restrict ");
13867c2aad20Sopenharmony_ci			break;
13877c2aad20Sopenharmony_ci		default:
13887c2aad20Sopenharmony_ci			return;
13897c2aad20Sopenharmony_ci		}
13907c2aad20Sopenharmony_ci		decl_stack->cnt--;
13917c2aad20Sopenharmony_ci	}
13927c2aad20Sopenharmony_ci}
13937c2aad20Sopenharmony_ci
13947c2aad20Sopenharmony_cistatic void btf_dump_drop_mods(struct btf_dump *d, struct id_stack *decl_stack)
13957c2aad20Sopenharmony_ci{
13967c2aad20Sopenharmony_ci	const struct btf_type *t;
13977c2aad20Sopenharmony_ci	__u32 id;
13987c2aad20Sopenharmony_ci
13997c2aad20Sopenharmony_ci	while (decl_stack->cnt) {
14007c2aad20Sopenharmony_ci		id = decl_stack->ids[decl_stack->cnt - 1];
14017c2aad20Sopenharmony_ci		t = btf__type_by_id(d->btf, id);
14027c2aad20Sopenharmony_ci		if (!btf_is_mod(t))
14037c2aad20Sopenharmony_ci			return;
14047c2aad20Sopenharmony_ci		decl_stack->cnt--;
14057c2aad20Sopenharmony_ci	}
14067c2aad20Sopenharmony_ci}
14077c2aad20Sopenharmony_ci
14087c2aad20Sopenharmony_cistatic void btf_dump_emit_name(const struct btf_dump *d,
14097c2aad20Sopenharmony_ci			       const char *name, bool last_was_ptr)
14107c2aad20Sopenharmony_ci{
14117c2aad20Sopenharmony_ci	bool separate = name[0] && !last_was_ptr;
14127c2aad20Sopenharmony_ci
14137c2aad20Sopenharmony_ci	btf_dump_printf(d, "%s%s", separate ? " " : "", name);
14147c2aad20Sopenharmony_ci}
14157c2aad20Sopenharmony_ci
14167c2aad20Sopenharmony_cistatic void btf_dump_emit_type_chain(struct btf_dump *d,
14177c2aad20Sopenharmony_ci				     struct id_stack *decls,
14187c2aad20Sopenharmony_ci				     const char *fname, int lvl)
14197c2aad20Sopenharmony_ci{
14207c2aad20Sopenharmony_ci	/*
14217c2aad20Sopenharmony_ci	 * last_was_ptr is used to determine if we need to separate pointer
14227c2aad20Sopenharmony_ci	 * asterisk (*) from previous part of type signature with space, so
14237c2aad20Sopenharmony_ci	 * that we get `int ***`, instead of `int * * *`. We default to true
14247c2aad20Sopenharmony_ci	 * for cases where we have single pointer in a chain. E.g., in ptr ->
14257c2aad20Sopenharmony_ci	 * func_proto case. func_proto will start a new emit_type_chain call
14267c2aad20Sopenharmony_ci	 * with just ptr, which should be emitted as (*) or (*<fname>), so we
14277c2aad20Sopenharmony_ci	 * don't want to prepend space for that last pointer.
14287c2aad20Sopenharmony_ci	 */
14297c2aad20Sopenharmony_ci	bool last_was_ptr = true;
14307c2aad20Sopenharmony_ci	const struct btf_type *t;
14317c2aad20Sopenharmony_ci	const char *name;
14327c2aad20Sopenharmony_ci	__u16 kind;
14337c2aad20Sopenharmony_ci	__u32 id;
14347c2aad20Sopenharmony_ci
14357c2aad20Sopenharmony_ci	while (decls->cnt) {
14367c2aad20Sopenharmony_ci		id = decls->ids[--decls->cnt];
14377c2aad20Sopenharmony_ci		if (id == 0) {
14387c2aad20Sopenharmony_ci			/* VOID is a special snowflake */
14397c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14407c2aad20Sopenharmony_ci			btf_dump_printf(d, "void");
14417c2aad20Sopenharmony_ci			last_was_ptr = false;
14427c2aad20Sopenharmony_ci			continue;
14437c2aad20Sopenharmony_ci		}
14447c2aad20Sopenharmony_ci
14457c2aad20Sopenharmony_ci		t = btf__type_by_id(d->btf, id);
14467c2aad20Sopenharmony_ci		kind = btf_kind(t);
14477c2aad20Sopenharmony_ci
14487c2aad20Sopenharmony_ci		switch (kind) {
14497c2aad20Sopenharmony_ci		case BTF_KIND_INT:
14507c2aad20Sopenharmony_ci		case BTF_KIND_FLOAT:
14517c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14527c2aad20Sopenharmony_ci			name = btf_name_of(d, t->name_off);
14537c2aad20Sopenharmony_ci			btf_dump_printf(d, "%s", name);
14547c2aad20Sopenharmony_ci			break;
14557c2aad20Sopenharmony_ci		case BTF_KIND_STRUCT:
14567c2aad20Sopenharmony_ci		case BTF_KIND_UNION:
14577c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14587c2aad20Sopenharmony_ci			/* inline anonymous struct/union */
14597c2aad20Sopenharmony_ci			if (t->name_off == 0 && !d->skip_anon_defs)
14607c2aad20Sopenharmony_ci				btf_dump_emit_struct_def(d, id, t, lvl);
14617c2aad20Sopenharmony_ci			else
14627c2aad20Sopenharmony_ci				btf_dump_emit_struct_fwd(d, id, t);
14637c2aad20Sopenharmony_ci			break;
14647c2aad20Sopenharmony_ci		case BTF_KIND_ENUM:
14657c2aad20Sopenharmony_ci		case BTF_KIND_ENUM64:
14667c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14677c2aad20Sopenharmony_ci			/* inline anonymous enum */
14687c2aad20Sopenharmony_ci			if (t->name_off == 0 && !d->skip_anon_defs)
14697c2aad20Sopenharmony_ci				btf_dump_emit_enum_def(d, id, t, lvl);
14707c2aad20Sopenharmony_ci			else
14717c2aad20Sopenharmony_ci				btf_dump_emit_enum_fwd(d, id, t);
14727c2aad20Sopenharmony_ci			break;
14737c2aad20Sopenharmony_ci		case BTF_KIND_FWD:
14747c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14757c2aad20Sopenharmony_ci			btf_dump_emit_fwd_def(d, id, t);
14767c2aad20Sopenharmony_ci			break;
14777c2aad20Sopenharmony_ci		case BTF_KIND_TYPEDEF:
14787c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14797c2aad20Sopenharmony_ci			btf_dump_printf(d, "%s", btf_dump_ident_name(d, id));
14807c2aad20Sopenharmony_ci			break;
14817c2aad20Sopenharmony_ci		case BTF_KIND_PTR:
14827c2aad20Sopenharmony_ci			btf_dump_printf(d, "%s", last_was_ptr ? "*" : " *");
14837c2aad20Sopenharmony_ci			break;
14847c2aad20Sopenharmony_ci		case BTF_KIND_VOLATILE:
14857c2aad20Sopenharmony_ci			btf_dump_printf(d, " volatile");
14867c2aad20Sopenharmony_ci			break;
14877c2aad20Sopenharmony_ci		case BTF_KIND_CONST:
14887c2aad20Sopenharmony_ci			btf_dump_printf(d, " const");
14897c2aad20Sopenharmony_ci			break;
14907c2aad20Sopenharmony_ci		case BTF_KIND_RESTRICT:
14917c2aad20Sopenharmony_ci			btf_dump_printf(d, " restrict");
14927c2aad20Sopenharmony_ci			break;
14937c2aad20Sopenharmony_ci		case BTF_KIND_TYPE_TAG:
14947c2aad20Sopenharmony_ci			btf_dump_emit_mods(d, decls);
14957c2aad20Sopenharmony_ci			name = btf_name_of(d, t->name_off);
14967c2aad20Sopenharmony_ci			btf_dump_printf(d, " __attribute__((btf_type_tag(\"%s\")))", name);
14977c2aad20Sopenharmony_ci			break;
14987c2aad20Sopenharmony_ci		case BTF_KIND_ARRAY: {
14997c2aad20Sopenharmony_ci			const struct btf_array *a = btf_array(t);
15007c2aad20Sopenharmony_ci			const struct btf_type *next_t;
15017c2aad20Sopenharmony_ci			__u32 next_id;
15027c2aad20Sopenharmony_ci			bool multidim;
15037c2aad20Sopenharmony_ci			/*
15047c2aad20Sopenharmony_ci			 * GCC has a bug
15057c2aad20Sopenharmony_ci			 * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=8354)
15067c2aad20Sopenharmony_ci			 * which causes it to emit extra const/volatile
15077c2aad20Sopenharmony_ci			 * modifiers for an array, if array's element type has
15087c2aad20Sopenharmony_ci			 * const/volatile modifiers. Clang doesn't do that.
15097c2aad20Sopenharmony_ci			 * In general, it doesn't seem very meaningful to have
15107c2aad20Sopenharmony_ci			 * a const/volatile modifier for array, so we are
15117c2aad20Sopenharmony_ci			 * going to silently skip them here.
15127c2aad20Sopenharmony_ci			 */
15137c2aad20Sopenharmony_ci			btf_dump_drop_mods(d, decls);
15147c2aad20Sopenharmony_ci
15157c2aad20Sopenharmony_ci			if (decls->cnt == 0) {
15167c2aad20Sopenharmony_ci				btf_dump_emit_name(d, fname, last_was_ptr);
15177c2aad20Sopenharmony_ci				btf_dump_printf(d, "[%u]", a->nelems);
15187c2aad20Sopenharmony_ci				return;
15197c2aad20Sopenharmony_ci			}
15207c2aad20Sopenharmony_ci
15217c2aad20Sopenharmony_ci			next_id = decls->ids[decls->cnt - 1];
15227c2aad20Sopenharmony_ci			next_t = btf__type_by_id(d->btf, next_id);
15237c2aad20Sopenharmony_ci			multidim = btf_is_array(next_t);
15247c2aad20Sopenharmony_ci			/* we need space if we have named non-pointer */
15257c2aad20Sopenharmony_ci			if (fname[0] && !last_was_ptr)
15267c2aad20Sopenharmony_ci				btf_dump_printf(d, " ");
15277c2aad20Sopenharmony_ci			/* no parentheses for multi-dimensional array */
15287c2aad20Sopenharmony_ci			if (!multidim)
15297c2aad20Sopenharmony_ci				btf_dump_printf(d, "(");
15307c2aad20Sopenharmony_ci			btf_dump_emit_type_chain(d, decls, fname, lvl);
15317c2aad20Sopenharmony_ci			if (!multidim)
15327c2aad20Sopenharmony_ci				btf_dump_printf(d, ")");
15337c2aad20Sopenharmony_ci			btf_dump_printf(d, "[%u]", a->nelems);
15347c2aad20Sopenharmony_ci			return;
15357c2aad20Sopenharmony_ci		}
15367c2aad20Sopenharmony_ci		case BTF_KIND_FUNC_PROTO: {
15377c2aad20Sopenharmony_ci			const struct btf_param *p = btf_params(t);
15387c2aad20Sopenharmony_ci			__u16 vlen = btf_vlen(t);
15397c2aad20Sopenharmony_ci			int i;
15407c2aad20Sopenharmony_ci
15417c2aad20Sopenharmony_ci			/*
15427c2aad20Sopenharmony_ci			 * GCC emits extra volatile qualifier for
15437c2aad20Sopenharmony_ci			 * __attribute__((noreturn)) function pointers. Clang
15447c2aad20Sopenharmony_ci			 * doesn't do it. It's a GCC quirk for backwards
15457c2aad20Sopenharmony_ci			 * compatibility with code written for GCC <2.5. So,
15467c2aad20Sopenharmony_ci			 * similarly to extra qualifiers for array, just drop
15477c2aad20Sopenharmony_ci			 * them, instead of handling them.
15487c2aad20Sopenharmony_ci			 */
15497c2aad20Sopenharmony_ci			btf_dump_drop_mods(d, decls);
15507c2aad20Sopenharmony_ci			if (decls->cnt) {
15517c2aad20Sopenharmony_ci				btf_dump_printf(d, " (");
15527c2aad20Sopenharmony_ci				btf_dump_emit_type_chain(d, decls, fname, lvl);
15537c2aad20Sopenharmony_ci				btf_dump_printf(d, ")");
15547c2aad20Sopenharmony_ci			} else {
15557c2aad20Sopenharmony_ci				btf_dump_emit_name(d, fname, last_was_ptr);
15567c2aad20Sopenharmony_ci			}
15577c2aad20Sopenharmony_ci			btf_dump_printf(d, "(");
15587c2aad20Sopenharmony_ci			/*
15597c2aad20Sopenharmony_ci			 * Clang for BPF target generates func_proto with no
15607c2aad20Sopenharmony_ci			 * args as a func_proto with a single void arg (e.g.,
15617c2aad20Sopenharmony_ci			 * `int (*f)(void)` vs just `int (*f)()`). We are
15627c2aad20Sopenharmony_ci			 * going to pretend there are no args for such case.
15637c2aad20Sopenharmony_ci			 */
15647c2aad20Sopenharmony_ci			if (vlen == 1 && p->type == 0) {
15657c2aad20Sopenharmony_ci				btf_dump_printf(d, ")");
15667c2aad20Sopenharmony_ci				return;
15677c2aad20Sopenharmony_ci			}
15687c2aad20Sopenharmony_ci
15697c2aad20Sopenharmony_ci			for (i = 0; i < vlen; i++, p++) {
15707c2aad20Sopenharmony_ci				if (i > 0)
15717c2aad20Sopenharmony_ci					btf_dump_printf(d, ", ");
15727c2aad20Sopenharmony_ci
15737c2aad20Sopenharmony_ci				/* last arg of type void is vararg */
15747c2aad20Sopenharmony_ci				if (i == vlen - 1 && p->type == 0) {
15757c2aad20Sopenharmony_ci					btf_dump_printf(d, "...");
15767c2aad20Sopenharmony_ci					break;
15777c2aad20Sopenharmony_ci				}
15787c2aad20Sopenharmony_ci
15797c2aad20Sopenharmony_ci				name = btf_name_of(d, p->name_off);
15807c2aad20Sopenharmony_ci				btf_dump_emit_type_decl(d, p->type, name, lvl);
15817c2aad20Sopenharmony_ci			}
15827c2aad20Sopenharmony_ci
15837c2aad20Sopenharmony_ci			btf_dump_printf(d, ")");
15847c2aad20Sopenharmony_ci			return;
15857c2aad20Sopenharmony_ci		}
15867c2aad20Sopenharmony_ci		default:
15877c2aad20Sopenharmony_ci			pr_warn("unexpected type in decl chain, kind:%u, id:[%u]\n",
15887c2aad20Sopenharmony_ci				kind, id);
15897c2aad20Sopenharmony_ci			return;
15907c2aad20Sopenharmony_ci		}
15917c2aad20Sopenharmony_ci
15927c2aad20Sopenharmony_ci		last_was_ptr = kind == BTF_KIND_PTR;
15937c2aad20Sopenharmony_ci	}
15947c2aad20Sopenharmony_ci
15957c2aad20Sopenharmony_ci	btf_dump_emit_name(d, fname, last_was_ptr);
15967c2aad20Sopenharmony_ci}
15977c2aad20Sopenharmony_ci
15987c2aad20Sopenharmony_ci/* show type name as (type_name) */
15997c2aad20Sopenharmony_cistatic void btf_dump_emit_type_cast(struct btf_dump *d, __u32 id,
16007c2aad20Sopenharmony_ci				    bool top_level)
16017c2aad20Sopenharmony_ci{
16027c2aad20Sopenharmony_ci	const struct btf_type *t;
16037c2aad20Sopenharmony_ci
16047c2aad20Sopenharmony_ci	/* for array members, we don't bother emitting type name for each
16057c2aad20Sopenharmony_ci	 * member to avoid the redundancy of
16067c2aad20Sopenharmony_ci	 * .name = (char[4])[(char)'f',(char)'o',(char)'o',]
16077c2aad20Sopenharmony_ci	 */
16087c2aad20Sopenharmony_ci	if (d->typed_dump->is_array_member)
16097c2aad20Sopenharmony_ci		return;
16107c2aad20Sopenharmony_ci
16117c2aad20Sopenharmony_ci	/* avoid type name specification for variable/section; it will be done
16127c2aad20Sopenharmony_ci	 * for the associated variable value(s).
16137c2aad20Sopenharmony_ci	 */
16147c2aad20Sopenharmony_ci	t = btf__type_by_id(d->btf, id);
16157c2aad20Sopenharmony_ci	if (btf_is_var(t) || btf_is_datasec(t))
16167c2aad20Sopenharmony_ci		return;
16177c2aad20Sopenharmony_ci
16187c2aad20Sopenharmony_ci	if (top_level)
16197c2aad20Sopenharmony_ci		btf_dump_printf(d, "(");
16207c2aad20Sopenharmony_ci
16217c2aad20Sopenharmony_ci	d->skip_anon_defs = true;
16227c2aad20Sopenharmony_ci	d->strip_mods = true;
16237c2aad20Sopenharmony_ci	btf_dump_emit_type_decl(d, id, "", 0);
16247c2aad20Sopenharmony_ci	d->strip_mods = false;
16257c2aad20Sopenharmony_ci	d->skip_anon_defs = false;
16267c2aad20Sopenharmony_ci
16277c2aad20Sopenharmony_ci	if (top_level)
16287c2aad20Sopenharmony_ci		btf_dump_printf(d, ")");
16297c2aad20Sopenharmony_ci}
16307c2aad20Sopenharmony_ci
16317c2aad20Sopenharmony_ci/* return number of duplicates (occurrences) of a given name */
16327c2aad20Sopenharmony_cistatic size_t btf_dump_name_dups(struct btf_dump *d, struct hashmap *name_map,
16337c2aad20Sopenharmony_ci				 const char *orig_name)
16347c2aad20Sopenharmony_ci{
16357c2aad20Sopenharmony_ci	char *old_name, *new_name;
16367c2aad20Sopenharmony_ci	size_t dup_cnt = 0;
16377c2aad20Sopenharmony_ci	int err;
16387c2aad20Sopenharmony_ci
16397c2aad20Sopenharmony_ci	new_name = strdup(orig_name);
16407c2aad20Sopenharmony_ci	if (!new_name)
16417c2aad20Sopenharmony_ci		return 1;
16427c2aad20Sopenharmony_ci
16437c2aad20Sopenharmony_ci	(void)hashmap__find(name_map, orig_name, &dup_cnt);
16447c2aad20Sopenharmony_ci	dup_cnt++;
16457c2aad20Sopenharmony_ci
16467c2aad20Sopenharmony_ci	err = hashmap__set(name_map, new_name, dup_cnt, &old_name, NULL);
16477c2aad20Sopenharmony_ci	if (err)
16487c2aad20Sopenharmony_ci		free(new_name);
16497c2aad20Sopenharmony_ci
16507c2aad20Sopenharmony_ci	free(old_name);
16517c2aad20Sopenharmony_ci
16527c2aad20Sopenharmony_ci	return dup_cnt;
16537c2aad20Sopenharmony_ci}
16547c2aad20Sopenharmony_ci
16557c2aad20Sopenharmony_cistatic const char *btf_dump_resolve_name(struct btf_dump *d, __u32 id,
16567c2aad20Sopenharmony_ci					 struct hashmap *name_map)
16577c2aad20Sopenharmony_ci{
16587c2aad20Sopenharmony_ci	struct btf_dump_type_aux_state *s = &d->type_states[id];
16597c2aad20Sopenharmony_ci	const struct btf_type *t = btf__type_by_id(d->btf, id);
16607c2aad20Sopenharmony_ci	const char *orig_name = btf_name_of(d, t->name_off);
16617c2aad20Sopenharmony_ci	const char **cached_name = &d->cached_names[id];
16627c2aad20Sopenharmony_ci	size_t dup_cnt;
16637c2aad20Sopenharmony_ci
16647c2aad20Sopenharmony_ci	if (t->name_off == 0)
16657c2aad20Sopenharmony_ci		return "";
16667c2aad20Sopenharmony_ci
16677c2aad20Sopenharmony_ci	if (s->name_resolved)
16687c2aad20Sopenharmony_ci		return *cached_name ? *cached_name : orig_name;
16697c2aad20Sopenharmony_ci
16707c2aad20Sopenharmony_ci	if (btf_is_fwd(t) || (btf_is_enum(t) && btf_vlen(t) == 0)) {
16717c2aad20Sopenharmony_ci		s->name_resolved = 1;
16727c2aad20Sopenharmony_ci		return orig_name;
16737c2aad20Sopenharmony_ci	}
16747c2aad20Sopenharmony_ci
16757c2aad20Sopenharmony_ci	dup_cnt = btf_dump_name_dups(d, name_map, orig_name);
16767c2aad20Sopenharmony_ci	if (dup_cnt > 1) {
16777c2aad20Sopenharmony_ci		const size_t max_len = 256;
16787c2aad20Sopenharmony_ci		char new_name[max_len];
16797c2aad20Sopenharmony_ci
16807c2aad20Sopenharmony_ci		snprintf(new_name, max_len, "%s___%zu", orig_name, dup_cnt);
16817c2aad20Sopenharmony_ci		*cached_name = strdup(new_name);
16827c2aad20Sopenharmony_ci	}
16837c2aad20Sopenharmony_ci
16847c2aad20Sopenharmony_ci	s->name_resolved = 1;
16857c2aad20Sopenharmony_ci	return *cached_name ? *cached_name : orig_name;
16867c2aad20Sopenharmony_ci}
16877c2aad20Sopenharmony_ci
16887c2aad20Sopenharmony_cistatic const char *btf_dump_type_name(struct btf_dump *d, __u32 id)
16897c2aad20Sopenharmony_ci{
16907c2aad20Sopenharmony_ci	return btf_dump_resolve_name(d, id, d->type_names);
16917c2aad20Sopenharmony_ci}
16927c2aad20Sopenharmony_ci
16937c2aad20Sopenharmony_cistatic const char *btf_dump_ident_name(struct btf_dump *d, __u32 id)
16947c2aad20Sopenharmony_ci{
16957c2aad20Sopenharmony_ci	return btf_dump_resolve_name(d, id, d->ident_names);
16967c2aad20Sopenharmony_ci}
16977c2aad20Sopenharmony_ci
16987c2aad20Sopenharmony_cistatic int btf_dump_dump_type_data(struct btf_dump *d,
16997c2aad20Sopenharmony_ci				   const char *fname,
17007c2aad20Sopenharmony_ci				   const struct btf_type *t,
17017c2aad20Sopenharmony_ci				   __u32 id,
17027c2aad20Sopenharmony_ci				   const void *data,
17037c2aad20Sopenharmony_ci				   __u8 bits_offset,
17047c2aad20Sopenharmony_ci				   __u8 bit_sz);
17057c2aad20Sopenharmony_ci
17067c2aad20Sopenharmony_cistatic const char *btf_dump_data_newline(struct btf_dump *d)
17077c2aad20Sopenharmony_ci{
17087c2aad20Sopenharmony_ci	return d->typed_dump->compact || d->typed_dump->depth == 0 ? "" : "\n";
17097c2aad20Sopenharmony_ci}
17107c2aad20Sopenharmony_ci
17117c2aad20Sopenharmony_cistatic const char *btf_dump_data_delim(struct btf_dump *d)
17127c2aad20Sopenharmony_ci{
17137c2aad20Sopenharmony_ci	return d->typed_dump->depth == 0 ? "" : ",";
17147c2aad20Sopenharmony_ci}
17157c2aad20Sopenharmony_ci
17167c2aad20Sopenharmony_cistatic void btf_dump_data_pfx(struct btf_dump *d)
17177c2aad20Sopenharmony_ci{
17187c2aad20Sopenharmony_ci	int i, lvl = d->typed_dump->indent_lvl + d->typed_dump->depth;
17197c2aad20Sopenharmony_ci
17207c2aad20Sopenharmony_ci	if (d->typed_dump->compact)
17217c2aad20Sopenharmony_ci		return;
17227c2aad20Sopenharmony_ci
17237c2aad20Sopenharmony_ci	for (i = 0; i < lvl; i++)
17247c2aad20Sopenharmony_ci		btf_dump_printf(d, "%s", d->typed_dump->indent_str);
17257c2aad20Sopenharmony_ci}
17267c2aad20Sopenharmony_ci
17277c2aad20Sopenharmony_ci/* A macro is used here as btf_type_value[s]() appends format specifiers
17287c2aad20Sopenharmony_ci * to the format specifier passed in; these do the work of appending
17297c2aad20Sopenharmony_ci * delimiters etc while the caller simply has to specify the type values
17307c2aad20Sopenharmony_ci * in the format specifier + value(s).
17317c2aad20Sopenharmony_ci */
17327c2aad20Sopenharmony_ci#define btf_dump_type_values(d, fmt, ...)				\
17337c2aad20Sopenharmony_ci	btf_dump_printf(d, fmt "%s%s",					\
17347c2aad20Sopenharmony_ci			##__VA_ARGS__,					\
17357c2aad20Sopenharmony_ci			btf_dump_data_delim(d),				\
17367c2aad20Sopenharmony_ci			btf_dump_data_newline(d))
17377c2aad20Sopenharmony_ci
17387c2aad20Sopenharmony_cistatic int btf_dump_unsupported_data(struct btf_dump *d,
17397c2aad20Sopenharmony_ci				     const struct btf_type *t,
17407c2aad20Sopenharmony_ci				     __u32 id)
17417c2aad20Sopenharmony_ci{
17427c2aad20Sopenharmony_ci	btf_dump_printf(d, "<unsupported kind:%u>", btf_kind(t));
17437c2aad20Sopenharmony_ci	return -ENOTSUP;
17447c2aad20Sopenharmony_ci}
17457c2aad20Sopenharmony_ci
17467c2aad20Sopenharmony_cistatic int btf_dump_get_bitfield_value(struct btf_dump *d,
17477c2aad20Sopenharmony_ci				       const struct btf_type *t,
17487c2aad20Sopenharmony_ci				       const void *data,
17497c2aad20Sopenharmony_ci				       __u8 bits_offset,
17507c2aad20Sopenharmony_ci				       __u8 bit_sz,
17517c2aad20Sopenharmony_ci				       __u64 *value)
17527c2aad20Sopenharmony_ci{
17537c2aad20Sopenharmony_ci	__u16 left_shift_bits, right_shift_bits;
17547c2aad20Sopenharmony_ci	const __u8 *bytes = data;
17557c2aad20Sopenharmony_ci	__u8 nr_copy_bits;
17567c2aad20Sopenharmony_ci	__u64 num = 0;
17577c2aad20Sopenharmony_ci	int i;
17587c2aad20Sopenharmony_ci
17597c2aad20Sopenharmony_ci	/* Maximum supported bitfield size is 64 bits */
17607c2aad20Sopenharmony_ci	if (t->size > 8) {
17617c2aad20Sopenharmony_ci		pr_warn("unexpected bitfield size %d\n", t->size);
17627c2aad20Sopenharmony_ci		return -EINVAL;
17637c2aad20Sopenharmony_ci	}
17647c2aad20Sopenharmony_ci
17657c2aad20Sopenharmony_ci	/* Bitfield value retrieval is done in two steps; first relevant bytes are
17667c2aad20Sopenharmony_ci	 * stored in num, then we left/right shift num to eliminate irrelevant bits.
17677c2aad20Sopenharmony_ci	 */
17687c2aad20Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
17697c2aad20Sopenharmony_ci	for (i = t->size - 1; i >= 0; i--)
17707c2aad20Sopenharmony_ci		num = num * 256 + bytes[i];
17717c2aad20Sopenharmony_ci	nr_copy_bits = bit_sz + bits_offset;
17727c2aad20Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
17737c2aad20Sopenharmony_ci	for (i = 0; i < t->size; i++)
17747c2aad20Sopenharmony_ci		num = num * 256 + bytes[i];
17757c2aad20Sopenharmony_ci	nr_copy_bits = t->size * 8 - bits_offset;
17767c2aad20Sopenharmony_ci#else
17777c2aad20Sopenharmony_ci# error "Unrecognized __BYTE_ORDER__"
17787c2aad20Sopenharmony_ci#endif
17797c2aad20Sopenharmony_ci	left_shift_bits = 64 - nr_copy_bits;
17807c2aad20Sopenharmony_ci	right_shift_bits = 64 - bit_sz;
17817c2aad20Sopenharmony_ci
17827c2aad20Sopenharmony_ci	*value = (num << left_shift_bits) >> right_shift_bits;
17837c2aad20Sopenharmony_ci
17847c2aad20Sopenharmony_ci	return 0;
17857c2aad20Sopenharmony_ci}
17867c2aad20Sopenharmony_ci
17877c2aad20Sopenharmony_cistatic int btf_dump_bitfield_check_zero(struct btf_dump *d,
17887c2aad20Sopenharmony_ci					const struct btf_type *t,
17897c2aad20Sopenharmony_ci					const void *data,
17907c2aad20Sopenharmony_ci					__u8 bits_offset,
17917c2aad20Sopenharmony_ci					__u8 bit_sz)
17927c2aad20Sopenharmony_ci{
17937c2aad20Sopenharmony_ci	__u64 check_num;
17947c2aad20Sopenharmony_ci	int err;
17957c2aad20Sopenharmony_ci
17967c2aad20Sopenharmony_ci	err = btf_dump_get_bitfield_value(d, t, data, bits_offset, bit_sz, &check_num);
17977c2aad20Sopenharmony_ci	if (err)
17987c2aad20Sopenharmony_ci		return err;
17997c2aad20Sopenharmony_ci	if (check_num == 0)
18007c2aad20Sopenharmony_ci		return -ENODATA;
18017c2aad20Sopenharmony_ci	return 0;
18027c2aad20Sopenharmony_ci}
18037c2aad20Sopenharmony_ci
18047c2aad20Sopenharmony_cistatic int btf_dump_bitfield_data(struct btf_dump *d,
18057c2aad20Sopenharmony_ci				  const struct btf_type *t,
18067c2aad20Sopenharmony_ci				  const void *data,
18077c2aad20Sopenharmony_ci				  __u8 bits_offset,
18087c2aad20Sopenharmony_ci				  __u8 bit_sz)
18097c2aad20Sopenharmony_ci{
18107c2aad20Sopenharmony_ci	__u64 print_num;
18117c2aad20Sopenharmony_ci	int err;
18127c2aad20Sopenharmony_ci
18137c2aad20Sopenharmony_ci	err = btf_dump_get_bitfield_value(d, t, data, bits_offset, bit_sz, &print_num);
18147c2aad20Sopenharmony_ci	if (err)
18157c2aad20Sopenharmony_ci		return err;
18167c2aad20Sopenharmony_ci
18177c2aad20Sopenharmony_ci	btf_dump_type_values(d, "0x%llx", (unsigned long long)print_num);
18187c2aad20Sopenharmony_ci
18197c2aad20Sopenharmony_ci	return 0;
18207c2aad20Sopenharmony_ci}
18217c2aad20Sopenharmony_ci
18227c2aad20Sopenharmony_ci/* ints, floats and ptrs */
18237c2aad20Sopenharmony_cistatic int btf_dump_base_type_check_zero(struct btf_dump *d,
18247c2aad20Sopenharmony_ci					 const struct btf_type *t,
18257c2aad20Sopenharmony_ci					 __u32 id,
18267c2aad20Sopenharmony_ci					 const void *data)
18277c2aad20Sopenharmony_ci{
18287c2aad20Sopenharmony_ci	static __u8 bytecmp[16] = {};
18297c2aad20Sopenharmony_ci	int nr_bytes;
18307c2aad20Sopenharmony_ci
18317c2aad20Sopenharmony_ci	/* For pointer types, pointer size is not defined on a per-type basis.
18327c2aad20Sopenharmony_ci	 * On dump creation however, we store the pointer size.
18337c2aad20Sopenharmony_ci	 */
18347c2aad20Sopenharmony_ci	if (btf_kind(t) == BTF_KIND_PTR)
18357c2aad20Sopenharmony_ci		nr_bytes = d->ptr_sz;
18367c2aad20Sopenharmony_ci	else
18377c2aad20Sopenharmony_ci		nr_bytes = t->size;
18387c2aad20Sopenharmony_ci
18397c2aad20Sopenharmony_ci	if (nr_bytes < 1 || nr_bytes > 16) {
18407c2aad20Sopenharmony_ci		pr_warn("unexpected size %d for id [%u]\n", nr_bytes, id);
18417c2aad20Sopenharmony_ci		return -EINVAL;
18427c2aad20Sopenharmony_ci	}
18437c2aad20Sopenharmony_ci
18447c2aad20Sopenharmony_ci	if (memcmp(data, bytecmp, nr_bytes) == 0)
18457c2aad20Sopenharmony_ci		return -ENODATA;
18467c2aad20Sopenharmony_ci	return 0;
18477c2aad20Sopenharmony_ci}
18487c2aad20Sopenharmony_ci
18497c2aad20Sopenharmony_cistatic bool ptr_is_aligned(const struct btf *btf, __u32 type_id,
18507c2aad20Sopenharmony_ci			   const void *data)
18517c2aad20Sopenharmony_ci{
18527c2aad20Sopenharmony_ci	int alignment = btf__align_of(btf, type_id);
18537c2aad20Sopenharmony_ci
18547c2aad20Sopenharmony_ci	if (alignment == 0)
18557c2aad20Sopenharmony_ci		return false;
18567c2aad20Sopenharmony_ci
18577c2aad20Sopenharmony_ci	return ((uintptr_t)data) % alignment == 0;
18587c2aad20Sopenharmony_ci}
18597c2aad20Sopenharmony_ci
18607c2aad20Sopenharmony_cistatic int btf_dump_int_data(struct btf_dump *d,
18617c2aad20Sopenharmony_ci			     const struct btf_type *t,
18627c2aad20Sopenharmony_ci			     __u32 type_id,
18637c2aad20Sopenharmony_ci			     const void *data,
18647c2aad20Sopenharmony_ci			     __u8 bits_offset)
18657c2aad20Sopenharmony_ci{
18667c2aad20Sopenharmony_ci	__u8 encoding = btf_int_encoding(t);
18677c2aad20Sopenharmony_ci	bool sign = encoding & BTF_INT_SIGNED;
18687c2aad20Sopenharmony_ci	char buf[16] __attribute__((aligned(16)));
18697c2aad20Sopenharmony_ci	int sz = t->size;
18707c2aad20Sopenharmony_ci
18717c2aad20Sopenharmony_ci	if (sz == 0 || sz > sizeof(buf)) {
18727c2aad20Sopenharmony_ci		pr_warn("unexpected size %d for id [%u]\n", sz, type_id);
18737c2aad20Sopenharmony_ci		return -EINVAL;
18747c2aad20Sopenharmony_ci	}
18757c2aad20Sopenharmony_ci
18767c2aad20Sopenharmony_ci	/* handle packed int data - accesses of integers not aligned on
18777c2aad20Sopenharmony_ci	 * int boundaries can cause problems on some platforms.
18787c2aad20Sopenharmony_ci	 */
18797c2aad20Sopenharmony_ci	if (!ptr_is_aligned(d->btf, type_id, data)) {
18807c2aad20Sopenharmony_ci		memcpy(buf, data, sz);
18817c2aad20Sopenharmony_ci		data = buf;
18827c2aad20Sopenharmony_ci	}
18837c2aad20Sopenharmony_ci
18847c2aad20Sopenharmony_ci	switch (sz) {
18857c2aad20Sopenharmony_ci	case 16: {
18867c2aad20Sopenharmony_ci		const __u64 *ints = data;
18877c2aad20Sopenharmony_ci		__u64 lsi, msi;
18887c2aad20Sopenharmony_ci
18897c2aad20Sopenharmony_ci		/* avoid use of __int128 as some 32-bit platforms do not
18907c2aad20Sopenharmony_ci		 * support it.
18917c2aad20Sopenharmony_ci		 */
18927c2aad20Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
18937c2aad20Sopenharmony_ci		lsi = ints[0];
18947c2aad20Sopenharmony_ci		msi = ints[1];
18957c2aad20Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
18967c2aad20Sopenharmony_ci		lsi = ints[1];
18977c2aad20Sopenharmony_ci		msi = ints[0];
18987c2aad20Sopenharmony_ci#else
18997c2aad20Sopenharmony_ci# error "Unrecognized __BYTE_ORDER__"
19007c2aad20Sopenharmony_ci#endif
19017c2aad20Sopenharmony_ci		if (msi == 0)
19027c2aad20Sopenharmony_ci			btf_dump_type_values(d, "0x%llx", (unsigned long long)lsi);
19037c2aad20Sopenharmony_ci		else
19047c2aad20Sopenharmony_ci			btf_dump_type_values(d, "0x%llx%016llx", (unsigned long long)msi,
19057c2aad20Sopenharmony_ci					     (unsigned long long)lsi);
19067c2aad20Sopenharmony_ci		break;
19077c2aad20Sopenharmony_ci	}
19087c2aad20Sopenharmony_ci	case 8:
19097c2aad20Sopenharmony_ci		if (sign)
19107c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%lld", *(long long *)data);
19117c2aad20Sopenharmony_ci		else
19127c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%llu", *(unsigned long long *)data);
19137c2aad20Sopenharmony_ci		break;
19147c2aad20Sopenharmony_ci	case 4:
19157c2aad20Sopenharmony_ci		if (sign)
19167c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%d", *(__s32 *)data);
19177c2aad20Sopenharmony_ci		else
19187c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%u", *(__u32 *)data);
19197c2aad20Sopenharmony_ci		break;
19207c2aad20Sopenharmony_ci	case 2:
19217c2aad20Sopenharmony_ci		if (sign)
19227c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%d", *(__s16 *)data);
19237c2aad20Sopenharmony_ci		else
19247c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%u", *(__u16 *)data);
19257c2aad20Sopenharmony_ci		break;
19267c2aad20Sopenharmony_ci	case 1:
19277c2aad20Sopenharmony_ci		if (d->typed_dump->is_array_char) {
19287c2aad20Sopenharmony_ci			/* check for null terminator */
19297c2aad20Sopenharmony_ci			if (d->typed_dump->is_array_terminated)
19307c2aad20Sopenharmony_ci				break;
19317c2aad20Sopenharmony_ci			if (*(char *)data == '\0') {
19327c2aad20Sopenharmony_ci				d->typed_dump->is_array_terminated = true;
19337c2aad20Sopenharmony_ci				break;
19347c2aad20Sopenharmony_ci			}
19357c2aad20Sopenharmony_ci			if (isprint(*(char *)data)) {
19367c2aad20Sopenharmony_ci				btf_dump_type_values(d, "'%c'", *(char *)data);
19377c2aad20Sopenharmony_ci				break;
19387c2aad20Sopenharmony_ci			}
19397c2aad20Sopenharmony_ci		}
19407c2aad20Sopenharmony_ci		if (sign)
19417c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%d", *(__s8 *)data);
19427c2aad20Sopenharmony_ci		else
19437c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%u", *(__u8 *)data);
19447c2aad20Sopenharmony_ci		break;
19457c2aad20Sopenharmony_ci	default:
19467c2aad20Sopenharmony_ci		pr_warn("unexpected sz %d for id [%u]\n", sz, type_id);
19477c2aad20Sopenharmony_ci		return -EINVAL;
19487c2aad20Sopenharmony_ci	}
19497c2aad20Sopenharmony_ci	return 0;
19507c2aad20Sopenharmony_ci}
19517c2aad20Sopenharmony_ci
19527c2aad20Sopenharmony_ciunion float_data {
19537c2aad20Sopenharmony_ci	long double ld;
19547c2aad20Sopenharmony_ci	double d;
19557c2aad20Sopenharmony_ci	float f;
19567c2aad20Sopenharmony_ci};
19577c2aad20Sopenharmony_ci
19587c2aad20Sopenharmony_cistatic int btf_dump_float_data(struct btf_dump *d,
19597c2aad20Sopenharmony_ci			       const struct btf_type *t,
19607c2aad20Sopenharmony_ci			       __u32 type_id,
19617c2aad20Sopenharmony_ci			       const void *data)
19627c2aad20Sopenharmony_ci{
19637c2aad20Sopenharmony_ci	const union float_data *flp = data;
19647c2aad20Sopenharmony_ci	union float_data fl;
19657c2aad20Sopenharmony_ci	int sz = t->size;
19667c2aad20Sopenharmony_ci
19677c2aad20Sopenharmony_ci	/* handle unaligned data; copy to local union */
19687c2aad20Sopenharmony_ci	if (!ptr_is_aligned(d->btf, type_id, data)) {
19697c2aad20Sopenharmony_ci		memcpy(&fl, data, sz);
19707c2aad20Sopenharmony_ci		flp = &fl;
19717c2aad20Sopenharmony_ci	}
19727c2aad20Sopenharmony_ci
19737c2aad20Sopenharmony_ci	switch (sz) {
19747c2aad20Sopenharmony_ci	case 16:
19757c2aad20Sopenharmony_ci		btf_dump_type_values(d, "%Lf", flp->ld);
19767c2aad20Sopenharmony_ci		break;
19777c2aad20Sopenharmony_ci	case 8:
19787c2aad20Sopenharmony_ci		btf_dump_type_values(d, "%lf", flp->d);
19797c2aad20Sopenharmony_ci		break;
19807c2aad20Sopenharmony_ci	case 4:
19817c2aad20Sopenharmony_ci		btf_dump_type_values(d, "%f", flp->f);
19827c2aad20Sopenharmony_ci		break;
19837c2aad20Sopenharmony_ci	default:
19847c2aad20Sopenharmony_ci		pr_warn("unexpected size %d for id [%u]\n", sz, type_id);
19857c2aad20Sopenharmony_ci		return -EINVAL;
19867c2aad20Sopenharmony_ci	}
19877c2aad20Sopenharmony_ci	return 0;
19887c2aad20Sopenharmony_ci}
19897c2aad20Sopenharmony_ci
19907c2aad20Sopenharmony_cistatic int btf_dump_var_data(struct btf_dump *d,
19917c2aad20Sopenharmony_ci			     const struct btf_type *v,
19927c2aad20Sopenharmony_ci			     __u32 id,
19937c2aad20Sopenharmony_ci			     const void *data)
19947c2aad20Sopenharmony_ci{
19957c2aad20Sopenharmony_ci	enum btf_func_linkage linkage = btf_var(v)->linkage;
19967c2aad20Sopenharmony_ci	const struct btf_type *t;
19977c2aad20Sopenharmony_ci	const char *l;
19987c2aad20Sopenharmony_ci	__u32 type_id;
19997c2aad20Sopenharmony_ci
20007c2aad20Sopenharmony_ci	switch (linkage) {
20017c2aad20Sopenharmony_ci	case BTF_FUNC_STATIC:
20027c2aad20Sopenharmony_ci		l = "static ";
20037c2aad20Sopenharmony_ci		break;
20047c2aad20Sopenharmony_ci	case BTF_FUNC_EXTERN:
20057c2aad20Sopenharmony_ci		l = "extern ";
20067c2aad20Sopenharmony_ci		break;
20077c2aad20Sopenharmony_ci	case BTF_FUNC_GLOBAL:
20087c2aad20Sopenharmony_ci	default:
20097c2aad20Sopenharmony_ci		l = "";
20107c2aad20Sopenharmony_ci		break;
20117c2aad20Sopenharmony_ci	}
20127c2aad20Sopenharmony_ci
20137c2aad20Sopenharmony_ci	/* format of output here is [linkage] [type] [varname] = (type)value,
20147c2aad20Sopenharmony_ci	 * for example "static int cpu_profile_flip = (int)1"
20157c2aad20Sopenharmony_ci	 */
20167c2aad20Sopenharmony_ci	btf_dump_printf(d, "%s", l);
20177c2aad20Sopenharmony_ci	type_id = v->type;
20187c2aad20Sopenharmony_ci	t = btf__type_by_id(d->btf, type_id);
20197c2aad20Sopenharmony_ci	btf_dump_emit_type_cast(d, type_id, false);
20207c2aad20Sopenharmony_ci	btf_dump_printf(d, " %s = ", btf_name_of(d, v->name_off));
20217c2aad20Sopenharmony_ci	return btf_dump_dump_type_data(d, NULL, t, type_id, data, 0, 0);
20227c2aad20Sopenharmony_ci}
20237c2aad20Sopenharmony_ci
20247c2aad20Sopenharmony_cistatic int btf_dump_array_data(struct btf_dump *d,
20257c2aad20Sopenharmony_ci			       const struct btf_type *t,
20267c2aad20Sopenharmony_ci			       __u32 id,
20277c2aad20Sopenharmony_ci			       const void *data)
20287c2aad20Sopenharmony_ci{
20297c2aad20Sopenharmony_ci	const struct btf_array *array = btf_array(t);
20307c2aad20Sopenharmony_ci	const struct btf_type *elem_type;
20317c2aad20Sopenharmony_ci	__u32 i, elem_type_id;
20327c2aad20Sopenharmony_ci	__s64 elem_size;
20337c2aad20Sopenharmony_ci	bool is_array_member;
20347c2aad20Sopenharmony_ci
20357c2aad20Sopenharmony_ci	elem_type_id = array->type;
20367c2aad20Sopenharmony_ci	elem_type = skip_mods_and_typedefs(d->btf, elem_type_id, NULL);
20377c2aad20Sopenharmony_ci	elem_size = btf__resolve_size(d->btf, elem_type_id);
20387c2aad20Sopenharmony_ci	if (elem_size <= 0) {
20397c2aad20Sopenharmony_ci		pr_warn("unexpected elem size %zd for array type [%u]\n",
20407c2aad20Sopenharmony_ci			(ssize_t)elem_size, id);
20417c2aad20Sopenharmony_ci		return -EINVAL;
20427c2aad20Sopenharmony_ci	}
20437c2aad20Sopenharmony_ci
20447c2aad20Sopenharmony_ci	if (btf_is_int(elem_type)) {
20457c2aad20Sopenharmony_ci		/*
20467c2aad20Sopenharmony_ci		 * BTF_INT_CHAR encoding never seems to be set for
20477c2aad20Sopenharmony_ci		 * char arrays, so if size is 1 and element is
20487c2aad20Sopenharmony_ci		 * printable as a char, we'll do that.
20497c2aad20Sopenharmony_ci		 */
20507c2aad20Sopenharmony_ci		if (elem_size == 1)
20517c2aad20Sopenharmony_ci			d->typed_dump->is_array_char = true;
20527c2aad20Sopenharmony_ci	}
20537c2aad20Sopenharmony_ci
20547c2aad20Sopenharmony_ci	/* note that we increment depth before calling btf_dump_print() below;
20557c2aad20Sopenharmony_ci	 * this is intentional.  btf_dump_data_newline() will not print a
20567c2aad20Sopenharmony_ci	 * newline for depth 0 (since this leaves us with trailing newlines
20577c2aad20Sopenharmony_ci	 * at the end of typed display), so depth is incremented first.
20587c2aad20Sopenharmony_ci	 * For similar reasons, we decrement depth before showing the closing
20597c2aad20Sopenharmony_ci	 * parenthesis.
20607c2aad20Sopenharmony_ci	 */
20617c2aad20Sopenharmony_ci	d->typed_dump->depth++;
20627c2aad20Sopenharmony_ci	btf_dump_printf(d, "[%s", btf_dump_data_newline(d));
20637c2aad20Sopenharmony_ci
20647c2aad20Sopenharmony_ci	/* may be a multidimensional array, so store current "is array member"
20657c2aad20Sopenharmony_ci	 * status so we can restore it correctly later.
20667c2aad20Sopenharmony_ci	 */
20677c2aad20Sopenharmony_ci	is_array_member = d->typed_dump->is_array_member;
20687c2aad20Sopenharmony_ci	d->typed_dump->is_array_member = true;
20697c2aad20Sopenharmony_ci	for (i = 0; i < array->nelems; i++, data += elem_size) {
20707c2aad20Sopenharmony_ci		if (d->typed_dump->is_array_terminated)
20717c2aad20Sopenharmony_ci			break;
20727c2aad20Sopenharmony_ci		btf_dump_dump_type_data(d, NULL, elem_type, elem_type_id, data, 0, 0);
20737c2aad20Sopenharmony_ci	}
20747c2aad20Sopenharmony_ci	d->typed_dump->is_array_member = is_array_member;
20757c2aad20Sopenharmony_ci	d->typed_dump->depth--;
20767c2aad20Sopenharmony_ci	btf_dump_data_pfx(d);
20777c2aad20Sopenharmony_ci	btf_dump_type_values(d, "]");
20787c2aad20Sopenharmony_ci
20797c2aad20Sopenharmony_ci	return 0;
20807c2aad20Sopenharmony_ci}
20817c2aad20Sopenharmony_ci
20827c2aad20Sopenharmony_cistatic int btf_dump_struct_data(struct btf_dump *d,
20837c2aad20Sopenharmony_ci				const struct btf_type *t,
20847c2aad20Sopenharmony_ci				__u32 id,
20857c2aad20Sopenharmony_ci				const void *data)
20867c2aad20Sopenharmony_ci{
20877c2aad20Sopenharmony_ci	const struct btf_member *m = btf_members(t);
20887c2aad20Sopenharmony_ci	__u16 n = btf_vlen(t);
20897c2aad20Sopenharmony_ci	int i, err = 0;
20907c2aad20Sopenharmony_ci
20917c2aad20Sopenharmony_ci	/* note that we increment depth before calling btf_dump_print() below;
20927c2aad20Sopenharmony_ci	 * this is intentional.  btf_dump_data_newline() will not print a
20937c2aad20Sopenharmony_ci	 * newline for depth 0 (since this leaves us with trailing newlines
20947c2aad20Sopenharmony_ci	 * at the end of typed display), so depth is incremented first.
20957c2aad20Sopenharmony_ci	 * For similar reasons, we decrement depth before showing the closing
20967c2aad20Sopenharmony_ci	 * parenthesis.
20977c2aad20Sopenharmony_ci	 */
20987c2aad20Sopenharmony_ci	d->typed_dump->depth++;
20997c2aad20Sopenharmony_ci	btf_dump_printf(d, "{%s", btf_dump_data_newline(d));
21007c2aad20Sopenharmony_ci
21017c2aad20Sopenharmony_ci	for (i = 0; i < n; i++, m++) {
21027c2aad20Sopenharmony_ci		const struct btf_type *mtype;
21037c2aad20Sopenharmony_ci		const char *mname;
21047c2aad20Sopenharmony_ci		__u32 moffset;
21057c2aad20Sopenharmony_ci		__u8 bit_sz;
21067c2aad20Sopenharmony_ci
21077c2aad20Sopenharmony_ci		mtype = btf__type_by_id(d->btf, m->type);
21087c2aad20Sopenharmony_ci		mname = btf_name_of(d, m->name_off);
21097c2aad20Sopenharmony_ci		moffset = btf_member_bit_offset(t, i);
21107c2aad20Sopenharmony_ci
21117c2aad20Sopenharmony_ci		bit_sz = btf_member_bitfield_size(t, i);
21127c2aad20Sopenharmony_ci		err = btf_dump_dump_type_data(d, mname, mtype, m->type, data + moffset / 8,
21137c2aad20Sopenharmony_ci					      moffset % 8, bit_sz);
21147c2aad20Sopenharmony_ci		if (err < 0)
21157c2aad20Sopenharmony_ci			return err;
21167c2aad20Sopenharmony_ci	}
21177c2aad20Sopenharmony_ci	d->typed_dump->depth--;
21187c2aad20Sopenharmony_ci	btf_dump_data_pfx(d);
21197c2aad20Sopenharmony_ci	btf_dump_type_values(d, "}");
21207c2aad20Sopenharmony_ci	return err;
21217c2aad20Sopenharmony_ci}
21227c2aad20Sopenharmony_ci
21237c2aad20Sopenharmony_ciunion ptr_data {
21247c2aad20Sopenharmony_ci	unsigned int p;
21257c2aad20Sopenharmony_ci	unsigned long long lp;
21267c2aad20Sopenharmony_ci};
21277c2aad20Sopenharmony_ci
21287c2aad20Sopenharmony_cistatic int btf_dump_ptr_data(struct btf_dump *d,
21297c2aad20Sopenharmony_ci			      const struct btf_type *t,
21307c2aad20Sopenharmony_ci			      __u32 id,
21317c2aad20Sopenharmony_ci			      const void *data)
21327c2aad20Sopenharmony_ci{
21337c2aad20Sopenharmony_ci	if (ptr_is_aligned(d->btf, id, data) && d->ptr_sz == sizeof(void *)) {
21347c2aad20Sopenharmony_ci		btf_dump_type_values(d, "%p", *(void **)data);
21357c2aad20Sopenharmony_ci	} else {
21367c2aad20Sopenharmony_ci		union ptr_data pt;
21377c2aad20Sopenharmony_ci
21387c2aad20Sopenharmony_ci		memcpy(&pt, data, d->ptr_sz);
21397c2aad20Sopenharmony_ci		if (d->ptr_sz == 4)
21407c2aad20Sopenharmony_ci			btf_dump_type_values(d, "0x%x", pt.p);
21417c2aad20Sopenharmony_ci		else
21427c2aad20Sopenharmony_ci			btf_dump_type_values(d, "0x%llx", pt.lp);
21437c2aad20Sopenharmony_ci	}
21447c2aad20Sopenharmony_ci	return 0;
21457c2aad20Sopenharmony_ci}
21467c2aad20Sopenharmony_ci
21477c2aad20Sopenharmony_cistatic int btf_dump_get_enum_value(struct btf_dump *d,
21487c2aad20Sopenharmony_ci				   const struct btf_type *t,
21497c2aad20Sopenharmony_ci				   const void *data,
21507c2aad20Sopenharmony_ci				   __u32 id,
21517c2aad20Sopenharmony_ci				   __s64 *value)
21527c2aad20Sopenharmony_ci{
21537c2aad20Sopenharmony_ci	bool is_signed = btf_kflag(t);
21547c2aad20Sopenharmony_ci
21557c2aad20Sopenharmony_ci	if (!ptr_is_aligned(d->btf, id, data)) {
21567c2aad20Sopenharmony_ci		__u64 val;
21577c2aad20Sopenharmony_ci		int err;
21587c2aad20Sopenharmony_ci
21597c2aad20Sopenharmony_ci		err = btf_dump_get_bitfield_value(d, t, data, 0, 0, &val);
21607c2aad20Sopenharmony_ci		if (err)
21617c2aad20Sopenharmony_ci			return err;
21627c2aad20Sopenharmony_ci		*value = (__s64)val;
21637c2aad20Sopenharmony_ci		return 0;
21647c2aad20Sopenharmony_ci	}
21657c2aad20Sopenharmony_ci
21667c2aad20Sopenharmony_ci	switch (t->size) {
21677c2aad20Sopenharmony_ci	case 8:
21687c2aad20Sopenharmony_ci		*value = *(__s64 *)data;
21697c2aad20Sopenharmony_ci		return 0;
21707c2aad20Sopenharmony_ci	case 4:
21717c2aad20Sopenharmony_ci		*value = is_signed ? (__s64)*(__s32 *)data : *(__u32 *)data;
21727c2aad20Sopenharmony_ci		return 0;
21737c2aad20Sopenharmony_ci	case 2:
21747c2aad20Sopenharmony_ci		*value = is_signed ? *(__s16 *)data : *(__u16 *)data;
21757c2aad20Sopenharmony_ci		return 0;
21767c2aad20Sopenharmony_ci	case 1:
21777c2aad20Sopenharmony_ci		*value = is_signed ? *(__s8 *)data : *(__u8 *)data;
21787c2aad20Sopenharmony_ci		return 0;
21797c2aad20Sopenharmony_ci	default:
21807c2aad20Sopenharmony_ci		pr_warn("unexpected size %d for enum, id:[%u]\n", t->size, id);
21817c2aad20Sopenharmony_ci		return -EINVAL;
21827c2aad20Sopenharmony_ci	}
21837c2aad20Sopenharmony_ci}
21847c2aad20Sopenharmony_ci
21857c2aad20Sopenharmony_cistatic int btf_dump_enum_data(struct btf_dump *d,
21867c2aad20Sopenharmony_ci			      const struct btf_type *t,
21877c2aad20Sopenharmony_ci			      __u32 id,
21887c2aad20Sopenharmony_ci			      const void *data)
21897c2aad20Sopenharmony_ci{
21907c2aad20Sopenharmony_ci	bool is_signed;
21917c2aad20Sopenharmony_ci	__s64 value;
21927c2aad20Sopenharmony_ci	int i, err;
21937c2aad20Sopenharmony_ci
21947c2aad20Sopenharmony_ci	err = btf_dump_get_enum_value(d, t, data, id, &value);
21957c2aad20Sopenharmony_ci	if (err)
21967c2aad20Sopenharmony_ci		return err;
21977c2aad20Sopenharmony_ci
21987c2aad20Sopenharmony_ci	is_signed = btf_kflag(t);
21997c2aad20Sopenharmony_ci	if (btf_is_enum(t)) {
22007c2aad20Sopenharmony_ci		const struct btf_enum *e;
22017c2aad20Sopenharmony_ci
22027c2aad20Sopenharmony_ci		for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
22037c2aad20Sopenharmony_ci			if (value != e->val)
22047c2aad20Sopenharmony_ci				continue;
22057c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
22067c2aad20Sopenharmony_ci			return 0;
22077c2aad20Sopenharmony_ci		}
22087c2aad20Sopenharmony_ci
22097c2aad20Sopenharmony_ci		btf_dump_type_values(d, is_signed ? "%d" : "%u", value);
22107c2aad20Sopenharmony_ci	} else {
22117c2aad20Sopenharmony_ci		const struct btf_enum64 *e;
22127c2aad20Sopenharmony_ci
22137c2aad20Sopenharmony_ci		for (i = 0, e = btf_enum64(t); i < btf_vlen(t); i++, e++) {
22147c2aad20Sopenharmony_ci			if (value != btf_enum64_value(e))
22157c2aad20Sopenharmony_ci				continue;
22167c2aad20Sopenharmony_ci			btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
22177c2aad20Sopenharmony_ci			return 0;
22187c2aad20Sopenharmony_ci		}
22197c2aad20Sopenharmony_ci
22207c2aad20Sopenharmony_ci		btf_dump_type_values(d, is_signed ? "%lldLL" : "%lluULL",
22217c2aad20Sopenharmony_ci				     (unsigned long long)value);
22227c2aad20Sopenharmony_ci	}
22237c2aad20Sopenharmony_ci	return 0;
22247c2aad20Sopenharmony_ci}
22257c2aad20Sopenharmony_ci
22267c2aad20Sopenharmony_cistatic int btf_dump_datasec_data(struct btf_dump *d,
22277c2aad20Sopenharmony_ci				 const struct btf_type *t,
22287c2aad20Sopenharmony_ci				 __u32 id,
22297c2aad20Sopenharmony_ci				 const void *data)
22307c2aad20Sopenharmony_ci{
22317c2aad20Sopenharmony_ci	const struct btf_var_secinfo *vsi;
22327c2aad20Sopenharmony_ci	const struct btf_type *var;
22337c2aad20Sopenharmony_ci	__u32 i;
22347c2aad20Sopenharmony_ci	int err;
22357c2aad20Sopenharmony_ci
22367c2aad20Sopenharmony_ci	btf_dump_type_values(d, "SEC(\"%s\") ", btf_name_of(d, t->name_off));
22377c2aad20Sopenharmony_ci
22387c2aad20Sopenharmony_ci	for (i = 0, vsi = btf_var_secinfos(t); i < btf_vlen(t); i++, vsi++) {
22397c2aad20Sopenharmony_ci		var = btf__type_by_id(d->btf, vsi->type);
22407c2aad20Sopenharmony_ci		err = btf_dump_dump_type_data(d, NULL, var, vsi->type, data + vsi->offset, 0, 0);
22417c2aad20Sopenharmony_ci		if (err < 0)
22427c2aad20Sopenharmony_ci			return err;
22437c2aad20Sopenharmony_ci		btf_dump_printf(d, ";");
22447c2aad20Sopenharmony_ci	}
22457c2aad20Sopenharmony_ci	return 0;
22467c2aad20Sopenharmony_ci}
22477c2aad20Sopenharmony_ci
22487c2aad20Sopenharmony_ci/* return size of type, or if base type overflows, return -E2BIG. */
22497c2aad20Sopenharmony_cistatic int btf_dump_type_data_check_overflow(struct btf_dump *d,
22507c2aad20Sopenharmony_ci					     const struct btf_type *t,
22517c2aad20Sopenharmony_ci					     __u32 id,
22527c2aad20Sopenharmony_ci					     const void *data,
22537c2aad20Sopenharmony_ci					     __u8 bits_offset,
22547c2aad20Sopenharmony_ci					     __u8 bit_sz)
22557c2aad20Sopenharmony_ci{
22567c2aad20Sopenharmony_ci	__s64 size;
22577c2aad20Sopenharmony_ci
22587c2aad20Sopenharmony_ci	if (bit_sz) {
22597c2aad20Sopenharmony_ci		/* bits_offset is at most 7. bit_sz is at most 128. */
22607c2aad20Sopenharmony_ci		__u8 nr_bytes = (bits_offset + bit_sz + 7) / 8;
22617c2aad20Sopenharmony_ci
22627c2aad20Sopenharmony_ci		/* When bit_sz is non zero, it is called from
22637c2aad20Sopenharmony_ci		 * btf_dump_struct_data() where it only cares about
22647c2aad20Sopenharmony_ci		 * negative error value.
22657c2aad20Sopenharmony_ci		 * Return nr_bytes in success case to make it
22667c2aad20Sopenharmony_ci		 * consistent as the regular integer case below.
22677c2aad20Sopenharmony_ci		 */
22687c2aad20Sopenharmony_ci		return data + nr_bytes > d->typed_dump->data_end ? -E2BIG : nr_bytes;
22697c2aad20Sopenharmony_ci	}
22707c2aad20Sopenharmony_ci
22717c2aad20Sopenharmony_ci	size = btf__resolve_size(d->btf, id);
22727c2aad20Sopenharmony_ci
22737c2aad20Sopenharmony_ci	if (size < 0 || size >= INT_MAX) {
22747c2aad20Sopenharmony_ci		pr_warn("unexpected size [%zu] for id [%u]\n",
22757c2aad20Sopenharmony_ci			(size_t)size, id);
22767c2aad20Sopenharmony_ci		return -EINVAL;
22777c2aad20Sopenharmony_ci	}
22787c2aad20Sopenharmony_ci
22797c2aad20Sopenharmony_ci	/* Only do overflow checking for base types; we do not want to
22807c2aad20Sopenharmony_ci	 * avoid showing part of a struct, union or array, even if we
22817c2aad20Sopenharmony_ci	 * do not have enough data to show the full object.  By
22827c2aad20Sopenharmony_ci	 * restricting overflow checking to base types we can ensure
22837c2aad20Sopenharmony_ci	 * that partial display succeeds, while avoiding overflowing
22847c2aad20Sopenharmony_ci	 * and using bogus data for display.
22857c2aad20Sopenharmony_ci	 */
22867c2aad20Sopenharmony_ci	t = skip_mods_and_typedefs(d->btf, id, NULL);
22877c2aad20Sopenharmony_ci	if (!t) {
22887c2aad20Sopenharmony_ci		pr_warn("unexpected error skipping mods/typedefs for id [%u]\n",
22897c2aad20Sopenharmony_ci			id);
22907c2aad20Sopenharmony_ci		return -EINVAL;
22917c2aad20Sopenharmony_ci	}
22927c2aad20Sopenharmony_ci
22937c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
22947c2aad20Sopenharmony_ci	case BTF_KIND_INT:
22957c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
22967c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
22977c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
22987c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
22997c2aad20Sopenharmony_ci		if (data + bits_offset / 8 + size > d->typed_dump->data_end)
23007c2aad20Sopenharmony_ci			return -E2BIG;
23017c2aad20Sopenharmony_ci		break;
23027c2aad20Sopenharmony_ci	default:
23037c2aad20Sopenharmony_ci		break;
23047c2aad20Sopenharmony_ci	}
23057c2aad20Sopenharmony_ci	return (int)size;
23067c2aad20Sopenharmony_ci}
23077c2aad20Sopenharmony_ci
23087c2aad20Sopenharmony_cistatic int btf_dump_type_data_check_zero(struct btf_dump *d,
23097c2aad20Sopenharmony_ci					 const struct btf_type *t,
23107c2aad20Sopenharmony_ci					 __u32 id,
23117c2aad20Sopenharmony_ci					 const void *data,
23127c2aad20Sopenharmony_ci					 __u8 bits_offset,
23137c2aad20Sopenharmony_ci					 __u8 bit_sz)
23147c2aad20Sopenharmony_ci{
23157c2aad20Sopenharmony_ci	__s64 value;
23167c2aad20Sopenharmony_ci	int i, err;
23177c2aad20Sopenharmony_ci
23187c2aad20Sopenharmony_ci	/* toplevel exceptions; we show zero values if
23197c2aad20Sopenharmony_ci	 * - we ask for them (emit_zeros)
23207c2aad20Sopenharmony_ci	 * - if we are at top-level so we see "struct empty { }"
23217c2aad20Sopenharmony_ci	 * - or if we are an array member and the array is non-empty and
23227c2aad20Sopenharmony_ci	 *   not a char array; we don't want to be in a situation where we
23237c2aad20Sopenharmony_ci	 *   have an integer array 0, 1, 0, 1 and only show non-zero values.
23247c2aad20Sopenharmony_ci	 *   If the array contains zeroes only, or is a char array starting
23257c2aad20Sopenharmony_ci	 *   with a '\0', the array-level check_zero() will prevent showing it;
23267c2aad20Sopenharmony_ci	 *   we are concerned with determining zero value at the array member
23277c2aad20Sopenharmony_ci	 *   level here.
23287c2aad20Sopenharmony_ci	 */
23297c2aad20Sopenharmony_ci	if (d->typed_dump->emit_zeroes || d->typed_dump->depth == 0 ||
23307c2aad20Sopenharmony_ci	    (d->typed_dump->is_array_member &&
23317c2aad20Sopenharmony_ci	     !d->typed_dump->is_array_char))
23327c2aad20Sopenharmony_ci		return 0;
23337c2aad20Sopenharmony_ci
23347c2aad20Sopenharmony_ci	t = skip_mods_and_typedefs(d->btf, id, NULL);
23357c2aad20Sopenharmony_ci
23367c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
23377c2aad20Sopenharmony_ci	case BTF_KIND_INT:
23387c2aad20Sopenharmony_ci		if (bit_sz)
23397c2aad20Sopenharmony_ci			return btf_dump_bitfield_check_zero(d, t, data, bits_offset, bit_sz);
23407c2aad20Sopenharmony_ci		return btf_dump_base_type_check_zero(d, t, id, data);
23417c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
23427c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
23437c2aad20Sopenharmony_ci		return btf_dump_base_type_check_zero(d, t, id, data);
23447c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY: {
23457c2aad20Sopenharmony_ci		const struct btf_array *array = btf_array(t);
23467c2aad20Sopenharmony_ci		const struct btf_type *elem_type;
23477c2aad20Sopenharmony_ci		__u32 elem_type_id, elem_size;
23487c2aad20Sopenharmony_ci		bool ischar;
23497c2aad20Sopenharmony_ci
23507c2aad20Sopenharmony_ci		elem_type_id = array->type;
23517c2aad20Sopenharmony_ci		elem_size = btf__resolve_size(d->btf, elem_type_id);
23527c2aad20Sopenharmony_ci		elem_type = skip_mods_and_typedefs(d->btf, elem_type_id, NULL);
23537c2aad20Sopenharmony_ci
23547c2aad20Sopenharmony_ci		ischar = btf_is_int(elem_type) && elem_size == 1;
23557c2aad20Sopenharmony_ci
23567c2aad20Sopenharmony_ci		/* check all elements; if _any_ element is nonzero, all
23577c2aad20Sopenharmony_ci		 * of array is displayed.  We make an exception however
23587c2aad20Sopenharmony_ci		 * for char arrays where the first element is 0; these
23597c2aad20Sopenharmony_ci		 * are considered zeroed also, even if later elements are
23607c2aad20Sopenharmony_ci		 * non-zero because the string is terminated.
23617c2aad20Sopenharmony_ci		 */
23627c2aad20Sopenharmony_ci		for (i = 0; i < array->nelems; i++) {
23637c2aad20Sopenharmony_ci			if (i == 0 && ischar && *(char *)data == 0)
23647c2aad20Sopenharmony_ci				return -ENODATA;
23657c2aad20Sopenharmony_ci			err = btf_dump_type_data_check_zero(d, elem_type,
23667c2aad20Sopenharmony_ci							    elem_type_id,
23677c2aad20Sopenharmony_ci							    data +
23687c2aad20Sopenharmony_ci							    (i * elem_size),
23697c2aad20Sopenharmony_ci							    bits_offset, 0);
23707c2aad20Sopenharmony_ci			if (err != -ENODATA)
23717c2aad20Sopenharmony_ci				return err;
23727c2aad20Sopenharmony_ci		}
23737c2aad20Sopenharmony_ci		return -ENODATA;
23747c2aad20Sopenharmony_ci	}
23757c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
23767c2aad20Sopenharmony_ci	case BTF_KIND_UNION: {
23777c2aad20Sopenharmony_ci		const struct btf_member *m = btf_members(t);
23787c2aad20Sopenharmony_ci		__u16 n = btf_vlen(t);
23797c2aad20Sopenharmony_ci
23807c2aad20Sopenharmony_ci		/* if any struct/union member is non-zero, the struct/union
23817c2aad20Sopenharmony_ci		 * is considered non-zero and dumped.
23827c2aad20Sopenharmony_ci		 */
23837c2aad20Sopenharmony_ci		for (i = 0; i < n; i++, m++) {
23847c2aad20Sopenharmony_ci			const struct btf_type *mtype;
23857c2aad20Sopenharmony_ci			__u32 moffset;
23867c2aad20Sopenharmony_ci
23877c2aad20Sopenharmony_ci			mtype = btf__type_by_id(d->btf, m->type);
23887c2aad20Sopenharmony_ci			moffset = btf_member_bit_offset(t, i);
23897c2aad20Sopenharmony_ci
23907c2aad20Sopenharmony_ci			/* btf_int_bits() does not store member bitfield size;
23917c2aad20Sopenharmony_ci			 * bitfield size needs to be stored here so int display
23927c2aad20Sopenharmony_ci			 * of member can retrieve it.
23937c2aad20Sopenharmony_ci			 */
23947c2aad20Sopenharmony_ci			bit_sz = btf_member_bitfield_size(t, i);
23957c2aad20Sopenharmony_ci			err = btf_dump_type_data_check_zero(d, mtype, m->type, data + moffset / 8,
23967c2aad20Sopenharmony_ci							    moffset % 8, bit_sz);
23977c2aad20Sopenharmony_ci			if (err != ENODATA)
23987c2aad20Sopenharmony_ci				return err;
23997c2aad20Sopenharmony_ci		}
24007c2aad20Sopenharmony_ci		return -ENODATA;
24017c2aad20Sopenharmony_ci	}
24027c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
24037c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
24047c2aad20Sopenharmony_ci		err = btf_dump_get_enum_value(d, t, data, id, &value);
24057c2aad20Sopenharmony_ci		if (err)
24067c2aad20Sopenharmony_ci			return err;
24077c2aad20Sopenharmony_ci		if (value == 0)
24087c2aad20Sopenharmony_ci			return -ENODATA;
24097c2aad20Sopenharmony_ci		return 0;
24107c2aad20Sopenharmony_ci	default:
24117c2aad20Sopenharmony_ci		return 0;
24127c2aad20Sopenharmony_ci	}
24137c2aad20Sopenharmony_ci}
24147c2aad20Sopenharmony_ci
24157c2aad20Sopenharmony_ci/* returns size of data dumped, or error. */
24167c2aad20Sopenharmony_cistatic int btf_dump_dump_type_data(struct btf_dump *d,
24177c2aad20Sopenharmony_ci				   const char *fname,
24187c2aad20Sopenharmony_ci				   const struct btf_type *t,
24197c2aad20Sopenharmony_ci				   __u32 id,
24207c2aad20Sopenharmony_ci				   const void *data,
24217c2aad20Sopenharmony_ci				   __u8 bits_offset,
24227c2aad20Sopenharmony_ci				   __u8 bit_sz)
24237c2aad20Sopenharmony_ci{
24247c2aad20Sopenharmony_ci	int size, err = 0;
24257c2aad20Sopenharmony_ci
24267c2aad20Sopenharmony_ci	size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset, bit_sz);
24277c2aad20Sopenharmony_ci	if (size < 0)
24287c2aad20Sopenharmony_ci		return size;
24297c2aad20Sopenharmony_ci	err = btf_dump_type_data_check_zero(d, t, id, data, bits_offset, bit_sz);
24307c2aad20Sopenharmony_ci	if (err) {
24317c2aad20Sopenharmony_ci		/* zeroed data is expected and not an error, so simply skip
24327c2aad20Sopenharmony_ci		 * dumping such data.  Record other errors however.
24337c2aad20Sopenharmony_ci		 */
24347c2aad20Sopenharmony_ci		if (err == -ENODATA)
24357c2aad20Sopenharmony_ci			return size;
24367c2aad20Sopenharmony_ci		return err;
24377c2aad20Sopenharmony_ci	}
24387c2aad20Sopenharmony_ci	btf_dump_data_pfx(d);
24397c2aad20Sopenharmony_ci
24407c2aad20Sopenharmony_ci	if (!d->typed_dump->skip_names) {
24417c2aad20Sopenharmony_ci		if (fname && strlen(fname) > 0)
24427c2aad20Sopenharmony_ci			btf_dump_printf(d, ".%s = ", fname);
24437c2aad20Sopenharmony_ci		btf_dump_emit_type_cast(d, id, true);
24447c2aad20Sopenharmony_ci	}
24457c2aad20Sopenharmony_ci
24467c2aad20Sopenharmony_ci	t = skip_mods_and_typedefs(d->btf, id, NULL);
24477c2aad20Sopenharmony_ci
24487c2aad20Sopenharmony_ci	switch (btf_kind(t)) {
24497c2aad20Sopenharmony_ci	case BTF_KIND_UNKN:
24507c2aad20Sopenharmony_ci	case BTF_KIND_FWD:
24517c2aad20Sopenharmony_ci	case BTF_KIND_FUNC:
24527c2aad20Sopenharmony_ci	case BTF_KIND_FUNC_PROTO:
24537c2aad20Sopenharmony_ci	case BTF_KIND_DECL_TAG:
24547c2aad20Sopenharmony_ci		err = btf_dump_unsupported_data(d, t, id);
24557c2aad20Sopenharmony_ci		break;
24567c2aad20Sopenharmony_ci	case BTF_KIND_INT:
24577c2aad20Sopenharmony_ci		if (bit_sz)
24587c2aad20Sopenharmony_ci			err = btf_dump_bitfield_data(d, t, data, bits_offset, bit_sz);
24597c2aad20Sopenharmony_ci		else
24607c2aad20Sopenharmony_ci			err = btf_dump_int_data(d, t, id, data, bits_offset);
24617c2aad20Sopenharmony_ci		break;
24627c2aad20Sopenharmony_ci	case BTF_KIND_FLOAT:
24637c2aad20Sopenharmony_ci		err = btf_dump_float_data(d, t, id, data);
24647c2aad20Sopenharmony_ci		break;
24657c2aad20Sopenharmony_ci	case BTF_KIND_PTR:
24667c2aad20Sopenharmony_ci		err = btf_dump_ptr_data(d, t, id, data);
24677c2aad20Sopenharmony_ci		break;
24687c2aad20Sopenharmony_ci	case BTF_KIND_ARRAY:
24697c2aad20Sopenharmony_ci		err = btf_dump_array_data(d, t, id, data);
24707c2aad20Sopenharmony_ci		break;
24717c2aad20Sopenharmony_ci	case BTF_KIND_STRUCT:
24727c2aad20Sopenharmony_ci	case BTF_KIND_UNION:
24737c2aad20Sopenharmony_ci		err = btf_dump_struct_data(d, t, id, data);
24747c2aad20Sopenharmony_ci		break;
24757c2aad20Sopenharmony_ci	case BTF_KIND_ENUM:
24767c2aad20Sopenharmony_ci	case BTF_KIND_ENUM64:
24777c2aad20Sopenharmony_ci		/* handle bitfield and int enum values */
24787c2aad20Sopenharmony_ci		if (bit_sz) {
24797c2aad20Sopenharmony_ci			__u64 print_num;
24807c2aad20Sopenharmony_ci			__s64 enum_val;
24817c2aad20Sopenharmony_ci
24827c2aad20Sopenharmony_ci			err = btf_dump_get_bitfield_value(d, t, data, bits_offset, bit_sz,
24837c2aad20Sopenharmony_ci							  &print_num);
24847c2aad20Sopenharmony_ci			if (err)
24857c2aad20Sopenharmony_ci				break;
24867c2aad20Sopenharmony_ci			enum_val = (__s64)print_num;
24877c2aad20Sopenharmony_ci			err = btf_dump_enum_data(d, t, id, &enum_val);
24887c2aad20Sopenharmony_ci		} else
24897c2aad20Sopenharmony_ci			err = btf_dump_enum_data(d, t, id, data);
24907c2aad20Sopenharmony_ci		break;
24917c2aad20Sopenharmony_ci	case BTF_KIND_VAR:
24927c2aad20Sopenharmony_ci		err = btf_dump_var_data(d, t, id, data);
24937c2aad20Sopenharmony_ci		break;
24947c2aad20Sopenharmony_ci	case BTF_KIND_DATASEC:
24957c2aad20Sopenharmony_ci		err = btf_dump_datasec_data(d, t, id, data);
24967c2aad20Sopenharmony_ci		break;
24977c2aad20Sopenharmony_ci	default:
24987c2aad20Sopenharmony_ci		pr_warn("unexpected kind [%u] for id [%u]\n",
24997c2aad20Sopenharmony_ci			BTF_INFO_KIND(t->info), id);
25007c2aad20Sopenharmony_ci		return -EINVAL;
25017c2aad20Sopenharmony_ci	}
25027c2aad20Sopenharmony_ci	if (err < 0)
25037c2aad20Sopenharmony_ci		return err;
25047c2aad20Sopenharmony_ci	return size;
25057c2aad20Sopenharmony_ci}
25067c2aad20Sopenharmony_ci
25077c2aad20Sopenharmony_ciint btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
25087c2aad20Sopenharmony_ci			     const void *data, size_t data_sz,
25097c2aad20Sopenharmony_ci			     const struct btf_dump_type_data_opts *opts)
25107c2aad20Sopenharmony_ci{
25117c2aad20Sopenharmony_ci	struct btf_dump_data typed_dump = {};
25127c2aad20Sopenharmony_ci	const struct btf_type *t;
25137c2aad20Sopenharmony_ci	int ret;
25147c2aad20Sopenharmony_ci
25157c2aad20Sopenharmony_ci	if (!OPTS_VALID(opts, btf_dump_type_data_opts))
25167c2aad20Sopenharmony_ci		return libbpf_err(-EINVAL);
25177c2aad20Sopenharmony_ci
25187c2aad20Sopenharmony_ci	t = btf__type_by_id(d->btf, id);
25197c2aad20Sopenharmony_ci	if (!t)
25207c2aad20Sopenharmony_ci		return libbpf_err(-ENOENT);
25217c2aad20Sopenharmony_ci
25227c2aad20Sopenharmony_ci	d->typed_dump = &typed_dump;
25237c2aad20Sopenharmony_ci	d->typed_dump->data_end = data + data_sz;
25247c2aad20Sopenharmony_ci	d->typed_dump->indent_lvl = OPTS_GET(opts, indent_level, 0);
25257c2aad20Sopenharmony_ci
25267c2aad20Sopenharmony_ci	/* default indent string is a tab */
25277c2aad20Sopenharmony_ci	if (!OPTS_GET(opts, indent_str, NULL))
25287c2aad20Sopenharmony_ci		d->typed_dump->indent_str[0] = '\t';
25297c2aad20Sopenharmony_ci	else
25307c2aad20Sopenharmony_ci		libbpf_strlcpy(d->typed_dump->indent_str, opts->indent_str,
25317c2aad20Sopenharmony_ci			       sizeof(d->typed_dump->indent_str));
25327c2aad20Sopenharmony_ci
25337c2aad20Sopenharmony_ci	d->typed_dump->compact = OPTS_GET(opts, compact, false);
25347c2aad20Sopenharmony_ci	d->typed_dump->skip_names = OPTS_GET(opts, skip_names, false);
25357c2aad20Sopenharmony_ci	d->typed_dump->emit_zeroes = OPTS_GET(opts, emit_zeroes, false);
25367c2aad20Sopenharmony_ci
25377c2aad20Sopenharmony_ci	ret = btf_dump_dump_type_data(d, NULL, t, id, data, 0, 0);
25387c2aad20Sopenharmony_ci
25397c2aad20Sopenharmony_ci	d->typed_dump = NULL;
25407c2aad20Sopenharmony_ci
25417c2aad20Sopenharmony_ci	return libbpf_err(ret);
25427c2aad20Sopenharmony_ci}
2543