bpftool: Update func representation to include function signature

Augment func= output for LOCSEC entries to include a mapping from
function signature to where parameters are stored; for example:

[290179] LOCSEC 'inline.text' vlen=524941
        func='task_pid_nr(tsk [reg0])' func_type_id=136691 loc_proto_type_id=136693 offset=2097226
        func='get_current()' func_type_id=136694 loc_proto_type_id=136695 offset=2097247
        func='arch_static_branch(key [address 0x2e275e8], branch [const 0x0])' func_type_id=136697 loc_proto_type_id=136700 offset=2097296

Fixes: 321562c34d ("bpftool: Add ability to dump LOC_PARAM, LOC_PROTO and LOCSEC")
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Quentin Monnet <qmo@kernel.org>
Link: https://patch.msgid.link/20260926175113.2368566-3-alan.maguire@oracle.com
This commit is contained in:
Alan Maguire 2026-09-26 18:51:12 +01:00 committed by Alexei Starovoitov
parent a3df11403e
commit 29f6453491
No known key found for this signature in database

View File

@ -150,6 +150,7 @@ static void btf_loc_param_raw_str(const struct btf_loc_param *p, __u32 vlen,
static void btf_loc_param_str(const struct btf_type *t, char *str, size_t sz)
{
const char *op = "", *prefix = "";
const struct btf_loc_param *p;
__u32 i = 0, vlen;
__u64 value;
@ -157,7 +158,6 @@ static void btf_loc_param_str(const struct btf_type *t, char *str, size_t sz)
bool negative = false;
char regs[32] = {};
char num[32] = {};
const char *op = "";
if (!t || !btf_is_loc_param(t)) {
snprintf(str, sz, "<invalid>");
@ -234,8 +234,12 @@ static void btf_loc_param_str(const struct btf_type *t, char *str, size_t sz)
(1ULL << bits) - value;
}
}
snprintf(num, sizeof(num), "0x%llx%s", (unsigned long long)value,
p->flags & BTF_LOC_PARAM_ADDR ? " (addr)" : "");
if (p->flags & BTF_LOC_PARAM_ADDR)
prefix = "address ";
else if (p->flags & BTF_LOC_PARAM_CONST)
prefix = "const ";
snprintf(num, sizeof(num), "0x%llx",
(unsigned long long)value);
}
if (i != vlen) {
btf_loc_param_raw_str(p, vlen, str, sz);
@ -244,14 +248,111 @@ static void btf_loc_param_str(const struct btf_type *t, char *str, size_t sz)
if (num[0])
op = regs[0] ? (negative ? " - " : " + ") : negative ? "-" : "";
snprintf(str, sz, "%s%s%s%s%s",
snprintf(str, sz, "%s%s%s%s%s%s",
p->flags & BTF_LOC_PARAM_DEREF ? "*(" : "",
prefix,
regs,
op,
num,
p->flags & BTF_LOC_PARAM_DEREF ? ")" : "");
}
static bool btf_locsec_append(char *str, size_t sz, size_t *off,
const char *suffix)
{
static const char nospace_suffix[] = "...";
bool space_left = true;
size_t left = 0, len;
if (*off >= sz || sz < sizeof(nospace_suffix))
return false;
left = sz - *off;
/*
* Copy as much of the string as we can in remaining space, and
* append "..." if we would have overrun.
*/
len = strlen(suffix) + 1;
if (len > left) {
len = left;
space_left = false;
}
memcpy(str + *off, suffix, len);
*off += len - 1;
if (!space_left)
memcpy(str + sz - sizeof(nospace_suffix), nospace_suffix, sizeof(nospace_suffix));
return space_left;
}
static void btf_locsec_func_str(const struct btf *btf,
const struct btf_loc *loc, char *str, size_t sz)
{
const struct btf_type *func, *func_proto, *loc_proto;
const struct btf_param *params;
const __u32 *loc_params;
const char *name;
__u32 i, vlen;
size_t off = 0;
if (!sz)
return;
str[0] = '\0';
func = btf__type_by_id(btf, loc->func);
if (!func || !btf_is_func(func))
goto invalid;
name = btf_str(btf, func->name_off);
func_proto = btf__type_by_id(btf, func->type);
loc_proto = btf__type_by_id(btf, loc->loc_proto);
if (!func_proto || !btf_is_func_proto(func_proto) ||
!loc_proto || !btf_is_loc_proto(loc_proto) ||
btf_vlen(func_proto) != btf_vlen(loc_proto))
goto invalid;
params = (const void *)(func_proto + 1);
loc_params = btf_loc_proto_params(loc_proto);
vlen = btf_vlen(func_proto);
if (!btf_locsec_append(str, sz, &off, name) ||
!btf_locsec_append(str, sz, &off, "("))
return;
for (i = 0; i < vlen; i++) {
const struct btf_type *param_loc;
char param_str[256] = {};
if (!params[i].type) {
/* Handle varargs func proto, must be last parameter */
if (i != vlen - 1)
goto invalid;
if (!btf_locsec_append(str, sz, &off, i ? ", " : "") ||
!btf_locsec_append(str, sz, &off, "..."))
return;
break;
} else if (loc_params[i]) {
param_loc = btf__type_by_id(btf, loc_params[i]);
btf_loc_param_str(param_loc, param_str, sizeof(param_str));
} else {
snprintf(param_str, sizeof(param_str), "<unavailable>");
}
if (!btf_locsec_append(str, sz, &off, i ? ", " : "") ||
!btf_locsec_append(str, sz, &off,
btf_str(btf, params[i].name_off)) ||
!btf_locsec_append(str, sz, &off, " [") ||
!btf_locsec_append(str, sz, &off, param_str) ||
!btf_locsec_append(str, sz, &off, "]"))
return;
}
(void) btf_locsec_append(str, sz, &off, ")");
return;
invalid:
snprintf(str, sz, "<invalid>");
}
static int dump_btf_type(const struct btf *btf, __u32 id,
const struct btf_type *t)
{
@ -617,22 +718,26 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
}
for (i = 0; i < vlen; i++, locs++) {
const struct btf_type *f = btf__type_by_id(btf, locs->func);
const struct btf_type *func;
const char *name = "<invalid>";
char func_str[1024] = {};
if (f && btf_is_func(f))
name = btf_str(btf, f->name_off);
func = btf__type_by_id(btf, locs->func);
if (func && btf_is_func(func))
name = btf_str(btf, func->name_off);
btf_locsec_func_str(btf, locs, func_str, sizeof(func_str));
if (json_output) {
jsonw_start_object(w);
jsonw_uint_field(w, "func_type_id", locs->func);
jsonw_string_field(w, "name", name);
jsonw_string_field(w, "func", func_str);
jsonw_uint_field(w, "loc_proto_type_id", locs->loc_proto);
jsonw_uint_field(w, "offset", locs->offset);
jsonw_end_object(w);
} else {
printf("\n\tname='%s' func_type_id=%u loc_proto_type_id=%u offset=%u",
name, locs->func, locs->loc_proto, locs->offset);
printf("\n\tfunc='%s' func_type_id=%u loc_proto_type_id=%u offset=%u",
func_str, locs->func, locs->loc_proto, locs->offset);
}
}
if (json_output)