Add support for new kinds to libbpf.  BTF_KIND_LOC_PARAM and
BTF_KIND_LOC_PROTO are dedup-able so add support for their
deduplication, whereas since BTF_KIND_LOCSEC contains a unique
offset it is not.  LOC_PARAM is considered a primary type
since it contains no external references; LOC_PROTO is a
reference type consisting of LOC_PARAM references so they
are handled in the primary and reference dedup phases
respectively.

For BTF field iteration, BTF_KIND_LOCSEC needs 2 m_offs[] values
for the associated KIND_FUNC and KIND_LOC_PROTO type ids in
each LOCSEC entry.

Add APIs to add location param, location prototypes and location
sections and btf_is_* tests, data accessors for each.

For BTF distillation we add location info to split BTF.

Signed-off-by: Alan Maguire <[email protected]>
---
 tools/lib/bpf/btf.c             | 372 +++++++++++++++++++++++++++++++-
 tools/lib/bpf/btf.h             |  50 +++++
 tools/lib/bpf/btf_dump.c        |   9 +
 tools/lib/bpf/btf_iter.c        |  22 ++
 tools/lib/bpf/libbpf.map        |   6 +
 tools/lib/bpf/libbpf_internal.h |   2 +-
 6 files changed, 457 insertions(+), 4 deletions(-)

diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index c783359977b4..9449f6f50f18 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -57,6 +57,9 @@ static struct btf_layout layouts[NR_BTF_KINDS] = {
 [BTF_KIND_DECL_TAG] =  {       sizeof(struct btf_decl_tag),    0,              
                0 },
 [BTF_KIND_TYPE_TAG] =  {       0,                              0,              
                0 },
 [BTF_KIND_ENUM64] =    {       0,                              sizeof(struct 
btf_enum64),      0 },
+[BTF_KIND_LOC_PARAM] = {       sizeof(struct btf_loc_param),   sizeof(__u32),  
                0 },
+[BTF_KIND_LOC_PROTO] = {       0,                              sizeof(__u32),  
                0 },
+[BTF_KIND_LOCSEC] =    {       0,                              sizeof(struct 
btf_loc),         0 },
 };
 
 struct btf {
@@ -486,6 +489,12 @@ static int btf_type_size(const struct btf *btf, const 
struct btf_type *t)
                return base_size + vlen * sizeof(struct btf_var_secinfo);
        case BTF_KIND_DECL_TAG:
                return base_size + sizeof(struct btf_decl_tag);
+       case BTF_KIND_LOC_PARAM:
+               return base_size + sizeof(struct btf_loc_param) + vlen * 
sizeof(__u32);
+       case BTF_KIND_LOC_PROTO:
+               return base_size + vlen * sizeof(__u32);
+       case BTF_KIND_LOCSEC:
+               return base_size + vlen * sizeof(struct btf_loc);
        default:
                return btf_type_size_unknown(btf, t);
        }
@@ -501,12 +510,15 @@ static void btf_bswap_type_base(struct btf_type *t)
 static int btf_bswap_type_rest(struct btf_type *t)
 {
        struct btf_var_secinfo *v;
+       struct btf_loc_param *lp;
        struct btf_enum64 *e64;
        struct btf_member *m;
        struct btf_array *a;
        struct btf_param *p;
        struct btf_enum *e;
+       struct btf_loc *l;
        __u32 vlen = btf_vlen(t);
+       __u32 *d;
        int i;
 
        switch (btf_kind(t)) {
@@ -569,6 +581,23 @@ static int btf_bswap_type_rest(struct btf_type *t)
        case BTF_KIND_DECL_TAG:
                btf_decl_tag(t)->component_idx = 
bswap_32(btf_decl_tag(t)->component_idx);
                return 0;
+       case BTF_KIND_LOC_PARAM:
+               lp = btf_loc_param(t);
+               lp->flags = bswap_32(lp->flags);
+               for (i = 0, d = (__u32 *)(lp + 1); i < vlen; i++, d++)
+                       *d = bswap_32(*d);
+               return 0;
+       case BTF_KIND_LOC_PROTO:
+               for (i = 0, d = btf_loc_proto_params(t); i < vlen; i++, d++)
+                       *d = bswap_32(*d);
+               return 0;
+       case BTF_KIND_LOCSEC:
+               for (i = 0, l = btf_locsec_locs(t); i < vlen; i++, l++) {
+                       l->func = bswap_32(l->func);
+                       l->loc_proto = bswap_32(l->loc_proto);
+                       l->offset = bswap_32(l->offset);
+               }
+               return 0;
        default:
                pr_debug("Unsupported BTF_KIND:%u\n", btf_kind(t));
                return -EINVAL;
@@ -745,6 +774,33 @@ static int btf_validate_type(const struct btf *btf, const 
struct btf_type *t, __
                }
                break;
        }
+       case BTF_KIND_LOC_PARAM:
+               break;
+       case BTF_KIND_LOC_PROTO: {
+               __u32 *p = btf_loc_proto_params(t);
+
+               n = btf_vlen(t);
+               for (i = 0; i < n; i++, p++) {
+                       err = btf_validate_id(btf, *p, id);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
+       case BTF_KIND_LOCSEC: {
+               const struct btf_loc *l = btf_locsec_locs(t);
+
+               n = btf_vlen(t);
+               for (i = 0; i < n; i++, l++) {
+                       if (!err)
+                               err = btf_validate_id(btf, l->func, id);
+                       if (!err)
+                               err = btf_validate_id(btf, l->loc_proto, id);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
        default:
                /* Kind may be represented in kind layout information. */
                if (btf_type_size_unknown(btf, t) < 0) {
@@ -3344,6 +3400,208 @@ int btf__add_decl_attr(struct btf *btf, const char 
*value, int ref_type_id,
        return btf_add_decl_tag(btf, value, ref_type_id, component_idx, 1);
 }
 
+/*
+ * Append new BTF_KIND_LOC_PARAM with specified size and flags.  Values are
+ * added via btf__add_loc_param_value().
+ *
+ * Returns:
+ *   -  >0, type ID of newly added BTF type;
+ *   - <0, on error.
+ */
+int btf__add_loc_param(struct btf *btf, __u32 size, __u32 flags)
+{
+       struct btf_loc_param *p;
+       struct btf_type *t;
+       int sz, err;
+
+       err = btf_ensure_modifiable(btf);
+       if (err)
+               return libbpf_err(err);
+
+       sz = sizeof(struct btf_type) + sizeof(*p);
+       t = btf_add_type_mem(btf, sz);
+       if (!t)
+               return libbpf_err(-ENOMEM);
+
+       t->name_off = 0;
+       t->info = btf_type_info(BTF_KIND_LOC_PARAM, 0, 0);
+       t->size = size;
+
+       p = btf_loc_param(t);
+       p->flags = flags;
+
+       return btf_commit_type(btf, sz);
+}
+
+int btf__add_loc_param_value(struct btf *btf, __u32 value)
+{
+       struct btf_type *t;
+       int sz, err;
+       __u32 *v;
+
+       /* last type should be BTF_KIND_LOC_PARAM */
+       if (btf->nr_types == 0)
+               return libbpf_err(-EINVAL);
+       t = btf_last_type(btf);
+       if (!btf_is_loc_param(t))
+               return libbpf_err(-EINVAL);
+
+       /* decompose and invalidate raw data */
+       err = btf_ensure_modifiable(btf);
+       if (err)
+               return libbpf_err(err);
+
+       sz = sizeof(value);
+       v = btf_add_type_mem(btf, sz);
+       if (!v)
+               return libbpf_err(-ENOMEM);
+       *v = value;
+
+       /* update parent type's vlen */
+       t = btf_last_type(btf);
+       err = btf_type_inc_vlen(t);
+       if (err)
+               return libbpf_err(err);
+
+       btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
+       return 0;
+}
+
+/*
+ * Append new BTF_KIND_LOC_PROTO
+ *
+ * The prototype is then populated with 0 or more BTF_KIND_LOC_PARAMs via
+ * btf__add_loc_proto_param(); similar to how btf__add_func_param() adds
+ * parameters to a FUNC_PROTO.
+ *
+ * Returns:
+ *   -  >0, type ID of newly added BTF type;
+ *   - <0, on error.
+ */
+int btf__add_loc_proto(struct btf *btf)
+{
+       struct btf_type *t;
+       int err;
+
+       err = btf_ensure_modifiable(btf);
+       if (err)
+               return libbpf_err(err);
+
+       t = btf_add_type_mem(btf, sizeof(struct btf_type));
+       if (!t)
+               return libbpf_err(-ENOMEM);
+
+       t->name_off = 0;
+       t->info = btf_type_info(BTF_KIND_LOC_PROTO, 0, 0);
+       t->size = 0;
+
+       return btf_commit_type(btf, sizeof(struct btf_type));
+}
+
+int btf__add_loc_proto_param(struct btf *btf, __u32 id)
+{
+       struct btf_type *t;
+       int sz, err;
+       __u32 *p;
+
+       if (validate_type_id(id))
+               return libbpf_err(-EINVAL);
+
+       /* last type should be BTF_KIND_LOC_PROTO */
+       if (btf->nr_types == 0)
+               return libbpf_err(-EINVAL);
+       t = btf_last_type(btf);
+       if (!btf_is_loc_proto(t))
+               return libbpf_err(-EINVAL);
+
+       /* decompose and invalidate raw data */
+       err = btf_ensure_modifiable(btf);
+       if (err)
+               return libbpf_err(err);
+
+       sz = sizeof(__u32);
+       p = btf_add_type_mem(btf, sz);
+       if (!p)
+               return libbpf_err(-ENOMEM);
+       *p = id;
+
+       /* update parent type's vlen */
+       t = btf_last_type(btf);
+       err = btf_type_inc_vlen(t);
+       if (err)
+               return libbpf_err(err);
+
+       btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
+       return 0;
+}
+
+int btf__add_locsec(struct btf *btf, const char *name)
+{
+       struct btf_type *t;
+       int name_off = 0;
+       int err;
+
+       err = btf_ensure_modifiable(btf);
+       if (err)
+               return libbpf_err(err);
+
+       t = btf_add_type_mem(btf, sizeof(struct btf_type));
+       if (!t)
+               return libbpf_err(-ENOMEM);
+
+       if (!str_is_empty(name)) {
+               name_off = btf__add_str(btf, name);
+               if (name_off < 0)
+                       return name_off;
+       }
+       t->name_off = name_off;
+       t->info = btf_type_info(BTF_KIND_LOCSEC, 0, 0);
+       t->size = 0;
+
+       return btf_commit_type(btf, sizeof(struct btf_type));
+}
+
+int btf__add_locsec_loc(struct btf *btf, __u32 func, __u32 loc_proto,
+                       __u32 offset)
+{
+       struct btf_type *t;
+       struct btf_loc *l;
+       int sz, err;
+
+       if (validate_type_id(func) || validate_type_id(loc_proto))
+               return libbpf_err(-EINVAL);
+
+       /* last type should be BTF_KIND_LOCSEC */
+       if (btf->nr_types == 0)
+               return libbpf_err(-EINVAL);
+       t = btf_last_type(btf);
+       if (!btf_is_locsec(t))
+               return libbpf_err(-EINVAL);
+
+       /* decompose and invalidate raw data */
+       err = btf_ensure_modifiable(btf);
+       if (err)
+               return libbpf_err(err);
+
+       sz = sizeof(*l);
+       l = btf_add_type_mem(btf, sz);
+       if (!l)
+               return libbpf_err(-ENOMEM);
+
+       l->func = func;
+       l->loc_proto = loc_proto;
+       l->offset = offset;
+
+       /* update parent type's vlen */
+       t = btf_last_type(btf);
+       err = btf_type_inc_vlen(t);
+       if (err)
+               return libbpf_err(err);
+
+       btf_hdr_update_type_len(btf, btf->hdr.type_len + sz);
+       return 0;
+}
+
 struct btf_ext_sec_info_param {
        __u32 off;
        __u32 len;
@@ -4114,8 +4372,8 @@ static struct btf_dedup *btf_dedup_new(struct btf *btf, 
const struct btf_dedup_o
        for (i = 1; i < type_cnt; i++) {
                struct btf_type *t = btf_type_by_id(d->btf, i);
 
-               /* VAR and DATASEC are never deduped and are self-canonical */
-               if (btf_is_var(t) || btf_is_datasec(t))
+               /* VAR, DATASEC and LOCSEC are never deduped and are 
self-canonical */
+               if (btf_is_var(t) || btf_is_datasec(t) || btf_is_locsec(t))
                        d->map[i] = i;
                else
                        d->map[i] = BTF_UNPROCESSED_ID;
@@ -4395,6 +4653,45 @@ static bool btf_compat_enum(struct btf_type *t1, struct 
btf_type *t2)
               btf_is_any_enum(t1) && btf_is_any_enum(t2);
 }
 
+static long btf_hash_loc_param(struct btf_type *t)
+{
+       long h = btf_hash_common(t);
+       __u32 *v = (__u32 *)btf_loc_param(t);
+       int i, vlen = btf_vlen(t);
+
+       for (i = 0; i <= vlen; i++, v++)
+               h = hash_combine(h, *v);
+       return h;
+}
+
+static long btf_hash_loc_proto(struct btf_type *t)
+{
+       __u32 *p = btf_loc_proto_params(t);
+       long h = btf_hash_common(t);
+       int i, vlen = btf_vlen(t);
+
+       for (i = 0; i < vlen; i++, p++)
+               h = hash_combine(h, *p);
+       return h;
+}
+
+static bool btf_equal_loc_param(struct btf_type *t1, struct btf_type *t2)
+{
+       struct btf_loc_param *p1 = btf_loc_param(t1);
+       struct btf_loc_param *p2 = btf_loc_param(t2);
+       __u32 *v1 = (__u32 *)(p1 + 1);
+       __u32 *v2 = (__u32 *)(p2 + 1);
+       int i, vlen = btf_vlen(t1);
+
+       if (!btf_equal_common(t1, t2))
+               return false;
+       for (i = 0; i < vlen; i++, v1++, v2++) {
+               if (*v1 != *v2)
+                       return false;
+       }
+       return true;
+}
+
 /*
  * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
  * as referenced type IDs equivalence is established separately during type
@@ -4622,6 +4919,12 @@ static int btf_dedup_prep(struct btf_dedup *d)
                case BTF_KIND_FUNC_PROTO:
                        h = btf_hash_fnproto(t);
                        break;
+               case BTF_KIND_LOC_PARAM:
+                       h = btf_hash_loc_param(t);
+                       break;
+               case BTF_KIND_LOC_PROTO:
+                       h = btf_hash_loc_proto(t);
+                       break;
                default:
                        pr_debug("unknown kind %d for type [%d]\n", 
btf_kind(t), type_id);
                        return -EINVAL;
@@ -4664,6 +4967,8 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 
type_id)
        case BTF_KIND_DATASEC:
        case BTF_KIND_DECL_TAG:
        case BTF_KIND_TYPE_TAG:
+       case BTF_KIND_LOC_PROTO:
+       case BTF_KIND_LOCSEC:
                return 0;
 
        case BTF_KIND_INT:
@@ -4713,6 +5018,18 @@ static int btf_dedup_prim_type(struct btf_dedup *d, 
__u32 type_id)
                }
                break;
 
+       case BTF_KIND_LOC_PARAM:
+               h = btf_hash_loc_param(t);
+               for_each_dedup_cand(d, hash_entry, h) {
+                       cand_id = hash_entry->value;
+                       cand = btf_type_by_id(d->btf, cand_id);
+                       if (btf_equal_loc_param(t, cand)) {
+                               new_id = cand_id;
+                               break;
+                       }
+               }
+               break;
+
        default:
                return -EINVAL;
        }
@@ -5145,6 +5462,13 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 
cand_id,
                return 1;
        }
 
+       case BTF_KIND_LOC_PARAM:
+               return btf_equal_loc_param(cand_type, canon_type);
+
+       case BTF_KIND_LOC_PROTO:
+       case BTF_KIND_LOCSEC:
+               return 0;
+
        default:
                return -EINVAL;
        }
@@ -5489,6 +5813,41 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 
type_id)
                break;
        }
 
+       case BTF_KIND_LOC_PROTO: {
+               __u32 *p1, *p2;
+               __u32 i, vlen;
+
+               p1 = btf_loc_proto_params(t);
+               vlen = btf_vlen(t);
+
+               for (i = 0; i < vlen; i++, p1++) {
+                       ref_type_id = btf_dedup_ref_type(d, *p1);
+                       if (ref_type_id < 0)
+                               return ref_type_id;
+                       *p1 = ref_type_id;
+               }
+
+               h = btf_hash_loc_proto(t);
+               for_each_dedup_cand(d, hash_entry, h) {
+                       cand_id = hash_entry->value;
+                       cand = btf_type_by_id(d->btf, cand_id);
+                       if (!btf_equal_common(t, cand))
+                               continue;
+                       vlen = btf_vlen(cand);
+                       p1 = btf_loc_proto_params(t);
+                       p2 = btf_loc_proto_params(cand);
+                       if (vlen == 0) {
+                               new_id = cand_id;
+                               break;
+                       }
+                       if (memcmp(p1, p2, vlen * sizeof(__u32)) == 0) {
+                               new_id = cand_id;
+                               break;
+                       }
+               }
+               break;
+       }
+
        default:
                return -EINVAL;
        }
@@ -5970,8 +6329,11 @@ static int btf_add_distilled_type_ids(struct btf_distill 
*dist, __u32 i)
                case BTF_KIND_CONST:
                case BTF_KIND_RESTRICT:
                case BTF_KIND_VOLATILE:
+               case BTF_KIND_FUNC:
                case BTF_KIND_FUNC_PROTO:
                case BTF_KIND_TYPE_TAG:
+               case BTF_KIND_LOC_PARAM:
+               case BTF_KIND_LOC_PROTO:
                        dist->id_map[*id] = *id;
                        break;
                default:
@@ -5997,7 +6359,7 @@ static int btf_add_distilled_type_ids(struct btf_distill 
*dist, __u32 i)
 
 static int btf_add_distilled_types(struct btf_distill *dist)
 {
-       bool adding_to_base = dist->pipe.dst->start_id == 1;
+       bool adding_to_base = dist->pipe.dst->base_btf == NULL;
        int id = btf__type_cnt(dist->pipe.dst);
        struct btf_type *t;
        int i, err = 0;
@@ -6065,8 +6427,12 @@ static int btf_add_distilled_types(struct btf_distill 
*dist)
                case BTF_KIND_CONST:
                case BTF_KIND_RESTRICT:
                case BTF_KIND_VOLATILE:
+               case BTF_KIND_FUNC:
                case BTF_KIND_FUNC_PROTO:
                case BTF_KIND_TYPE_TAG:
+               case BTF_KIND_LOC_PARAM:
+               case BTF_KIND_LOC_PROTO:
+               case BTF_KIND_LOCSEC:
                        /* All other types are added to split BTF. */
                        if (adding_to_base)
                                continue;
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index 587172c0de08..57f12630c5d1 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -274,6 +274,20 @@ LIBBPF_API int btf__add_decl_tag(struct btf *btf, const 
char *value, int ref_typ
 LIBBPF_API int btf__add_decl_attr(struct btf *btf, const char *value, int 
ref_type_id,
                                  int component_idx);
 
+/* location construction APIs */
+LIBBPF_API int btf__add_loc_param(struct btf *btf, __u32 size, __u32 flags);
+
+LIBBPF_API int btf__add_loc_param_value(struct btf *btf, __u32 value);
+
+LIBBPF_API int btf__add_loc_proto(struct btf *btf);
+
+LIBBPF_API int btf__add_loc_proto_param(struct btf *btf, __u32 id);
+
+LIBBPF_API int btf__add_locsec(struct btf *btf, const char *name);
+
+LIBBPF_API int btf__add_locsec_loc(struct btf *btf, __u32 func, __u32 
loc_proto,
+                                  __u32 offset);
+
 struct btf_dedup_opts {
        size_t sz;
        /* optional .BTF.ext info to dedup along the main BTF info */
@@ -431,6 +445,12 @@ btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
 #define BTF_KIND_DECL_TAG      17      /* Decl Tag */
 #define BTF_KIND_TYPE_TAG      18      /* Type Tag */
 #define BTF_KIND_ENUM64                19      /* Enum for up-to 64bit values 
*/
+#define BTF_KIND_LOC_PARAM     20      /* Parameter at location */
+#define BTF_KIND_LOC_PROTO     21      /* Parameter set at location */
+#define BTF_KIND_LOCSEC                22      /* Section containing location 
info */
+
+struct btf_loc_param;
+struct btf_loc;
 
 static inline __u16 btf_kind(const struct btf_type *t)
 {
@@ -569,6 +589,21 @@ static inline bool btf_is_any_enum(const struct btf_type 
*t)
        return btf_is_enum(t) || btf_is_enum64(t);
 }
 
+static inline bool btf_is_loc_param(const struct btf_type *t)
+{
+       return btf_kind(t) == BTF_KIND_LOC_PARAM;
+}
+
+static inline bool btf_is_loc_proto(const struct btf_type *t)
+{
+       return btf_kind(t) == BTF_KIND_LOC_PROTO;
+}
+
+static inline bool btf_is_locsec(const struct btf_type *t)
+{
+       return btf_kind(t) == BTF_KIND_LOCSEC;
+}
+
 static inline bool btf_kind_core_compat(const struct btf_type *t1,
                                        const struct btf_type *t2)
 {
@@ -683,6 +718,21 @@ static inline struct btf_decl_tag *btf_decl_tag(const 
struct btf_type *t)
        return (struct btf_decl_tag *)(t + 1);
 }
 
+static inline struct btf_loc_param *btf_loc_param(const struct btf_type *t)
+{
+       return (struct btf_loc_param *)(t + 1);
+}
+
+static inline __u32 *btf_loc_proto_params(const struct btf_type *t)
+{
+       return (__u32 *)(t + 1);
+}
+
+static inline struct btf_loc *btf_locsec_locs(const struct btf_type *t)
+{
+       return (struct btf_loc *)(t + 1);
+}
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
index 123c448f20c7..fa995c02a170 100644
--- a/tools/lib/bpf/btf_dump.c
+++ b/tools/lib/bpf/btf_dump.c
@@ -328,6 +328,9 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
                case BTF_KIND_ENUM64:
                case BTF_KIND_FWD:
                case BTF_KIND_FLOAT:
+               case BTF_KIND_LOC_PARAM:
+               case BTF_KIND_LOC_PROTO:
+               case BTF_KIND_LOCSEC:
                        break;
 
                case BTF_KIND_VOLATILE:
@@ -609,6 +612,9 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 
id, bool through_ptr)
        case BTF_KIND_VAR:
        case BTF_KIND_DATASEC:
        case BTF_KIND_DECL_TAG:
+       case BTF_KIND_LOC_PARAM:
+       case BTF_KIND_LOC_PROTO:
+       case BTF_KIND_LOCSEC:
                d->type_states[id].order_state = ORDERED;
                return 0;
 
@@ -2525,6 +2531,9 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
        case BTF_KIND_FUNC:
        case BTF_KIND_FUNC_PROTO:
        case BTF_KIND_DECL_TAG:
+       case BTF_KIND_LOC_PARAM:
+       case BTF_KIND_LOC_PROTO:
+       case BTF_KIND_LOCSEC:
                err = btf_dump_unsupported_data(d, t, id);
                break;
        case BTF_KIND_INT:
diff --git a/tools/lib/bpf/btf_iter.c b/tools/lib/bpf/btf_iter.c
index 9a6c822c2294..54428e422ec3 100644
--- a/tools/lib/bpf/btf_iter.c
+++ b/tools/lib/bpf/btf_iter.c
@@ -29,6 +29,7 @@ int btf_field_iter_init(struct btf_field_iter *it, struct 
btf_type *t,
                case BTF_KIND_FLOAT:
                case BTF_KIND_ENUM:
                case BTF_KIND_ENUM64:
+               case BTF_KIND_LOC_PARAM:
                        it->desc = (struct btf_field_desc) {};
                        break;
                case BTF_KIND_FWD:
@@ -71,6 +72,20 @@ int btf_field_iter_init(struct btf_field_iter *it, struct 
btf_type *t,
                                1, {offsetof(struct btf_var_secinfo, type)}
                        };
                        break;
+               case BTF_KIND_LOC_PROTO:
+                       it->desc = (struct btf_field_desc) {
+                               0, {},
+                               sizeof(__u32),
+                               1, {0}};
+                       break;
+               case BTF_KIND_LOCSEC:
+                       it->desc = (struct btf_field_desc) {
+                               0, {},
+                               sizeof(struct btf_loc),
+                               2, {offsetof(struct btf_loc, func),
+                                   offsetof(struct btf_loc, loc_proto)}};
+                       break;
+
                default:
                        return -EINVAL;
                }
@@ -94,6 +109,8 @@ int btf_field_iter_init(struct btf_field_iter *it, struct 
btf_type *t,
                case BTF_KIND_DECL_TAG:
                case BTF_KIND_TYPE_TAG:
                case BTF_KIND_DATASEC:
+               case BTF_KIND_LOC_PARAM:
+               case BTF_KIND_LOC_PROTO:
                        it->desc = (struct btf_field_desc) {
                                1, {offsetof(struct btf_type, name_off)}
                        };
@@ -127,6 +144,11 @@ int btf_field_iter_init(struct btf_field_iter *it, struct 
btf_type *t,
                                1, {offsetof(struct btf_param, name_off)}
                        };
                        break;
+               case BTF_KIND_LOCSEC:
+                       it->desc = (struct btf_field_desc) {
+                               1, {offsetof(struct btf_type, name_off)}
+                       };
+                       break;
                default:
                        return -EINVAL;
                }
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 08ab2ea881fb..7f51783df129 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -460,6 +460,12 @@ LIBBPF_1.8.0 {
        global:
                bpf_program__attach_tracing_multi;
                bpf_program__clone;
+               btf__add_loc_param;
+               btf__add_loc_param_value;
+               btf__add_loc_proto;
+               btf__add_loc_proto_param;
+               btf__add_locsec;
+               btf__add_locsec_loc;
                btf__find_by_name_kind_own;
                btf__new_empty_opts;
 } LIBBPF_1.7.0;
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index cb4d96233844..ebac8db1ccfd 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -580,7 +580,7 @@ struct btf_field_desc {
        /* member struct size, or zero, if no members */
        int m_sz;
        /* repeated per-member offsets */
-       int m_off_cnt, m_offs[1];
+       int m_off_cnt, m_offs[22];
 };
 
 struct btf_field_iter {
-- 
2.43.5


Reply via email to