This one-liner shouldn't fail like this:
# bpftrace -ve 't:irq:irq_handler_entry { @[args->name] = count(); }'
Struct/union of type '_tracepoint_irq_irq_handler_entry' does not contain a field named 'name'
# cat /sys/kernel/debug/tracing/events/irq/irq_handler_entry/format
name: irq_handler_entry
ID: 149
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int irq; offset:8; size:4; signed:1;
field:__data_loc char[] name; offset:12; size:4; signed:1;
print fmt: "irq=%d name=%s", REC->irq, __get_str(name)
I don't think the tracepoint args parser is handling the "__data_loc char[] name" entry.
Running with '-d' I can see the line field:__data_loc char[] name; is becoming int data_loc_name;:
./bpftrace -d -e 't:irq:irq_handler_entry { @[args->name] = count(); }'
#include <linux/types.h>
struct _tracepoint_irq_irq_handler_entry
{
unsigned short common_type;
unsigned char common_flags;
unsigned char common_preempt_count;
int common_pid;
int irq;
int data_loc_name;
};
Program
tracepoint:irq:irq_handler_entry
=
map: @
.
dereference
builtin: args
name
call: count
Struct/union of type '_tracepoint_irq_irq_handler_entry' does not contain a field named 'name'
But analyzing the code, this is intentional... (tracepoint_format_parser.cpp:99):
if (field_type.find("__data_loc") != std::string::npos)
{
field_type = "int";
field_name = "data_loc_" + field_name;
}
./bpftrace -e 't:irq:irq_handler_entry { @[args->data_loc_name] = count(); }'
Attaching 1 probe...
^C
@[655376]: 5
@[589840]: 12
@[1245200]: 201
@[524304]: 412
@[327696]: 4354
Ah, thanks. So -lv should show that, and not:
# bpftrace -lv tracepoint:irq:irq_handler_entry
tracepoint:irq:irq_handler_entry
int irq;
__data_loc char[] name;
But it also needs special processing:
# bpftrace -e 't:irq:irq_handler_entry { @[str(args->data_loc_name)] = count(); }'
Attaching 1 probe...
^C
@[]: 138
I don't think that should be null, and the offsets look suspicious. I think it needs special processing, hence the __get_str() call in the format file, which is in include/trace/trace_events.h.
@brendangregg I can try to implement this...
Fix the "-lv" is the easy part.
The "special processing" is what will be more challenge for me.
Would the idea be to add a new function "str_data_loc()" let's say?
There is a discussion about this __data_loc here:
"Accessing __string fields in tracepoints"
https://lists.linuxfoundation.org/pipermail/iovisor-dev/2017-February/000625.html
Ideally I wouldn't expose it to the user. So instead of "__data_loc char[] name", I'd expose it as "char *name", and bpftrace would remember that it's a data_loc (maybe by adding a is_data_loc bool to SizedType) and can then do he special processing -- probably by adding a function in irbuilderbpf.cpp to do it.
We do have some char *'s in tracepoints already:
bpftrace -lv 't:syscalls:sys_enter_openat'
tracepoint:syscalls:sys_enter_openat
int __syscall_nr;
int dfd;
const char * filename;
int flags;
umode_t mode;
I guess this would be a const char as well.
Just ran into this today. The suggestion by @brendangregg sounds good.
Note that bcc has this in src/cc/export/helpers.h:
#define TP_DATA_LOC_READ_CONST(dst, field, length) \
do { \
unsigned short __offset = args->data_loc_##field & 0xFFFF; \
bpf_probe_read((void *)dst, length, (char *)args + __offset); \
} while (0);
#define TP_DATA_LOC_READ(dst, field) \
do { \
unsigned short __offset = args->data_loc_##field & 0xFFFF; \
unsigned short __length = args->data_loc_##field >> 16; \
bpf_probe_read((void *)dst, __length, (char *)args + __offset); \
} while (0);
Most helpful comment
Just ran into this today. The suggestion by @brendangregg sounds good.