Bpftrace: tracepoint arguments are missing __data_loc char strings

Created on 2 Feb 2019  路  7Comments  路  Source: iovisor/bpftrace

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.

bug

Most helpful comment

Just ran into this today. The suggestion by @brendangregg sounds good.

All 7 comments

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);
Was this page helpful?
0 / 5 - 0 ratings