eBPF: tail calls - c

I'm playing with tail calls feature of BPF, and it seems the simple code doesn't get loaded:
struct bpf_map_def SEC("maps") jmp_table = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(u32),
.max_entries = 8,
};
SEC("sockops")
int bpf1(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf2(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf3(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf_main(struct bpf_sock_ops *sk_ops)
{
__u32 port = bpf_ntohl(sk_ops->remote_port);
switch (port) {
case 5000:
bpf_tail_call(sk_ops, &jmp_table, 1);
break;
case 6000:
bpf_tail_call(sk_ops, &jmp_table, 2);
break;
case 7000:
bpf_tail_call(sk_ops, &jmp_table, 3);
break;
}
sk_ops->reply = 0;
return 1;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;
So I compiled it with llv-3.8 and loaded with bpftool:
$ sudo ./bpftool prog load bpf_main.o /sys/fs/bpf/p1
libbpf: load bpf program failed: Invalid argument
libbpf: -- BEGIN DUMP LOG ---
libbpf:
unreachable insn 2
libbpf: -- END LOG --
libbpf: failed to load program 'sockops'
libbpf: failed to load object 'bpf_main.o'
Error: failed to load program
So man 2 bpf mentions that:
EINVAL For BPF_PROG_LOAD, indicates an attempt to load an invalid program. eBPF programs can be deemed invalid due to unrecognized instructions, the use of reserved fields, jumps out of range, infinite loops or calls of unknown functions.
I don't see what is wrong with this tiny simple program, also llvm-objdump fails:
$ llvm-objdump-3.8 -arch-name=bpf -disassemble ./tcp_metrics_kern.o
./tcp_metrics_kern.o: file format ELF64-unknown
LLVM ERROR: error: no disassembler for target bpfel-unknown-unknown
UPDATE 1
Following Qeole's advice I upgraded to clang-5.0, rebuilt my program and now it complains differently:
$ sudo ./bpftool prog load bpf_main.o /sys/fs/bpf/p1
libbpf: relocation failed: no 10 section
Error: failed to load program
Now I can investigate ELF sections:
$ llvm-objdump-5.0 -disassemble -source ./bpf_main.o
./bpf_main.o: file format ELF64-BPF
Disassembly of section sockops:
bpf1:
0: b7 00 00 00 01 00 00 00 r0 = 1
1: 95 00 00 00 00 00 00 00 exit
bpf2:
2: b7 00 00 00 01 00 00 00 r0 = 1
3: 95 00 00 00 00 00 00 00 exit
bpf3:
4: b7 00 00 00 01 00 00 00 r0 = 1
5: 95 00 00 00 00 00 00 00 exit
bpf_main:
...
Here are available sections:
$ llvm-objdump-5.0 -section-headers ./bpf_main.o
./bpf_main.o: file format ELF64-BPF
Sections:
Idx Name Size Address Type
0 00000000 0000000000000000
1 .strtab 000000a5 0000000000000000
2 .text 00000000 0000000000000000 TEXT DATA
3 sockops 000001f8 0000000000000000 TEXT DATA
4 .relsockops 00000030 0000000000000000
5 maps 0000001c 0000000000000000 DATA
6 .rodata.str1.16 00000021 0000000000000000 DATA
7 .rodata.str1.1 0000000e 0000000000000000 DATA
8 license 00000004 0000000000000000 DATA
9 version 00000004 0000000000000000 DATA
10 .eh_frame 00000090 0000000000000000 DATA
11 .rel.eh_frame 00000040 0000000000000000
12 .symtab 00000138 0000000000000000
It looks that bpftool can't find section .eh_frame?
UPDATE 2
I continue experimenting :-) First of all I updated libbpf with latest commit d77be68955475fc2321e73fe006240248f2f8fef fixing string comparison, then I rebuild the program with -fno-asynchronous-unwind-tables, this does not include .eh_frame section, and also I gave unique section names, e.g. sockops0, sockops1 etc. Now bpftool prog load .. succeeds but bpftool prog show dumps only a single program, the one that goes very first, in my case it is bpf1().
At the moment I can say that bpf_object__load_progs() reports obj->nr_programs as 4, this makes sense for my example.

Related

bpf_trace_printk causes program not loaded in kernel -- libbpf: Program 'xdp' contains unrecognized relo data pointing to section 6

following is my code and libbpf throws error that
libbpf: Program 'xdp' contains unrecognized relo data pointing to section 6
ERR: loading BPF-OBJ file(./k.o) (-2): No such file or directory
ERR: loading file: ./k.o
Why is that. This is how I am printing with bpf_trace_printk
bpf_trace_printk("hello\n",sizeof("hello\n"));
this is full code
#include <stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
/* Defines xdp_stats_map from packet04 */
#include "../common/xdp_stats_kern_user.h"
#include "../common/xdp_stats_kern.h"
#include <../common/parsing_helpers.h>
#include <bpf/bpf_helpers.h>
#define ETH_ALEN 6
#define MAX_ENTRIES 1000
/*struct {
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, MAX_ENTRIES);
} hash_map SEC(".maps");
*/
struct hash_elem {
int cnt;
struct bpf_spin_lock lock;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, struct hash_elem);
__uint(max_entries, 100);
} hash_map SEC(".maps");
struct a{struct bpf_spin_lock lock;};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, long);
__uint(max_entries, 2);
} hash_map1 SEC(".maps");
//static __u32 i=0;
struct icmphdr1
{
__u8 type; /* message type */
__u8 code; /* type sub-code */
__u16 checksum;
union
{
struct
{
__u16 id;
__u16 sequence;
} echo; /* echo datagram */
__u32 gateway; /* gateway address */
struct
{
__u16 __glibc_reserved;
__u16 mtu;
} frag; /* path mtu discovery */
} un;
};
SEC("xdp")
int xdp_prog_simple(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
__u16 h_proto;
if (eth + 1 > data_end)
return XDP_DROP;
h_proto = eth->h_proto;
if (h_proto == bpf_htons(ETH_P_IP))
{
struct iphdr *ip=(struct iphdr *)(eth+sizeof(struct ethhdr));
if(ip+1>data_end)
{
__u8 protocol_ip=ip->protocol;
if(protocol_ip==0x01)
{
struct icmphdr1 *icmp=(struct icmphdr1 *)(ip+sizeof(struct iphdr));
if(icmp+1>data_end)
{
__u8 type=icmp->type;
__u8 code=icmp->code;
if(type!=10 && code!=11)
bpf_trace_printk("hello\n",sizeof("hello\n"));
// if(type==8)
// if(code==0)
// bpf_trace_printk("code is 0\n",sizeof("code is 0\n"));
// bpf_trace_printk("icmp type:code = %d:%d\n",sizeof("icmp type:code = %d:%d\n"),type,code);
}
//__u32 key=i;
//__u64 val=bpf_ktime_get_ns();
//int x=bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
}
}
}
return XDP_DROP;
}
TL;DR
Do not call your helper like this:
// BAD
bpf_trace_printk("hello\n", sizeof("hello\n"));
or like this:
// BAD
const char *msg = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
But instead, declare your string as a dynamic array of characters:
// GOOD
char msg[] = "hello\n";
bpf_trace_printk(msg, sizeof(msg));
This will prevent clang from creating a relocation that libbpf cannot handle.
Explanations
Let's have a look at the object file, when passing the string directly:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
bpf_trace_printk("hello\n", sizeof("hello\n"));
return 0;
}
When doing this, clang puts the string into a read-only section, and requests a relocation. We can observe this with llvm-objdump. Let's inspect the relocations and disassemble the program:
$ clang -O2 -emit-llvm -c foo.c -o - | llc -march=bpf -filetype=obj -o foo.
$ llvm-objdump -r foo.o
foo.o: file format elf64-bpf
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000000 R_BPF_64_64 .rodata.str1.1
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
000000000000001c R_BPF_64_ABS64 .text
$ lvm-objdump --section=.text -D foo.o
foo.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo>:
0: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
2: b7 02 00 00 07 00 00 00 r2 = 7
3: 85 00 00 00 06 00 00 00 call 6
4: b7 00 00 00 00 00 00 00 r0 = 0
5: 95 00 00 00 00 00 00 00 exit
We note that the .text section, containing the program, starts with a single load r1 = 0: the register r1, containing the first argument to pass to the call to bpf_trace_printk() (call 6), is not set until this relocation happens.
But libbpf does not support this kind of relocations, this is why you get your error message:
Program 'xdp' contains unrecognized relo data pointing to section 6
The same can be observed with:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
const char* msg = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
return 0;
}
This is equivalent, clang creates a relocation too.
However, we can instead declare the string as a dynamic array of characters:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
char msg[] = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
return 0;
}
In that case, the array goes to the stack. No relocation happens. The .rodata.str1.1 section is not present in the file. We can check what llvm-objdump says:
$ clang -O2 -emit-llvm -c foo.c -o - | llc -march=bpf -filetype=obj -o foo.o
$ llvm-objdump -r foo.o
foo.o: file format elf64-bpf
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
000000000000001c R_BPF_64_ABS64 .text
$ lvm-objdump --section=.text -D foo.o
foo.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo>:
0: b7 01 00 00 6f 0a 00 00 r1 = 2671
1: 6b 1a fc ff 00 00 00 00 *(u16 *)(r10 - 4) = r1
2: b7 01 00 00 68 65 6c 6c r1 = 1819043176
3: 63 1a f8 ff 00 00 00 00 *(u32 *)(r10 - 8) = r1
4: b7 01 00 00 00 00 00 00 r1 = 0
5: 73 1a fe ff 00 00 00 00 *(u8 *)(r10 - 2) = r1
6: bf a1 00 00 00 00 00 00 r1 = r10
7: 07 01 00 00 f8 ff ff ff r1 += -8
8: b7 02 00 00 07 00 00 00 r2 = 7
9: 85 00 00 00 06 00 00 00 call 6
10: b7 00 00 00 00 00 00 00 r0 = 0
11: 95 00 00 00 00 00 00 00 exit
Here, we fill the stack (r10 is the stack pointer) with the characters of the string (68 65 6c 6c 6f 0a 00 00 is hello\n\0\0). Everything is processed in BPF, there is no relocation involved. And this works just fine.
Could we do better? Yes, with Linux 5.2 and older, we can avoid having the array on the stack by declaring the string as:
static const char msg[] = "hello\n";
This time, this results in a relocation to section .rodata, but one that libbpf does handle, through the support of static variables. More details are available here.
Generally speaking, BPF tips & tricks: the guide to bpf_trace_printk() and bpf_printk() is an excellent reference on the bpf_trace_printk() helper.

BPF verifier throws error "expected=map_ptr"

I'm writing a little eBPF program to set a flag whenever the tracepoint consume_skb is triggered. When I try to load it however, the BPF verifier complains, saying R1 type=inv expected=map_ptr when trying to access the map. I tried to follow the samples given in the linux kernel as closely as possible, but I am failing at even reading anything from the map.
eBPF program
#include <uapi/linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, u32);
__type(value, u32);
__uint(max_entries, 1);
} my_map SEC(".maps");
SEC("tracepoint/skb/consume_skb")
int bpf_sys(void *ctx)
{
int index = 0;
int *value;
value = bpf_map_lookup_elem(&my_map, &index);
if (!value)
{
return 1;
}
return 0;
}
char _license[] SEC("license") = "GPL";
loader, until point of failure
int main()
{
int bfd;
unsigned char buf[1024] = {};
struct bpf_insn *insn;
union bpf_attr attr = {};
unsigned char log_buf[4096] = {};
int pfd;
int n;
bfd = open("./test_bpf", O_RDONLY);
if (bfd < 0)
{
printf("open eBPF program error: %s\n", strerror(errno));
exit(-1);
}
n = read(bfd, buf, 1024);
close(bfd);
insn = (struct bpf_insn*)buf;
attr.prog_type = BPF_PROG_TYPE_TRACEPOINT;
attr.insns = (unsigned long)insn;
attr.insn_cnt = n / sizeof(struct bpf_insn);
attr.license = (unsigned long)"GPL";
attr.log_size = sizeof(log_buf);
attr.log_buf = (unsigned long)log_buf;
attr.log_level = 1;
pfd = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
if (pfd < 0)
{
printf("bpf syscall error: %s\n", strerror(errno));
printf("log_buf = %s\n", log_buf);
exit(-1);
}
...
llvm output
Disassembly of section tracepoint/skb/consume_skb:
0000000000000000 bpf_sys:
; {
0: b7 01 00 00 00 00 00 00 r1 = 0
; int index = 0;
1: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r1
2: bf a2 00 00 00 00 00 00 r2 = r10
3: 07 02 00 00 fc ff ff ff r2 += -4
; value = bpf_map_lookup_elem(&my_map, &index);
4: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
6: 85 00 00 00 01 00 00 00 call 1
7: bf 01 00 00 00 00 00 00 r1 = r0
8: b7 00 00 00 01 00 00 00 r0 = 1
; if (!value)
9: 15 01 01 00 00 00 00 00 if r1 == 0 goto +1 <LBB0_2>
10: b7 00 00 00 00 00 00 00 r0 = 0
0000000000000058 LBB0_2:
; }
11: 95 00 00 00 00 00 00 00 exit
Error when loading
bpf syscall error: Permission denied
log_buf = 0: (b7) r1 = 0
1: (63) *(u32 *)(r10 -4) = r1
last_idx 1 first_idx 0
regs=2 stack=0 before 0: (b7) r1 = 0
2: (bf) r2 = r10
3: (07) r2 += -4
4: (18) r1 = 0x0
6: (85) call bpf_map_lookup_elem#1
R1 type=inv expected=map_ptr
processed 6 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
Also, is there a better way to debug BPF error messages?
Issues
Parsing the bytecode
Your loader does not work, at least not directly on the object file compiled from your C code. It just reads from the file, does not parse for an ELF section where the bytecode would be contained. Apparently you're getting the verifier output for the correct eBPF bytecode, though; so I suspect you've been using it in a different way, or with some intermediate step.
Setting up the maps
With regards to your issue, your loader also misses the creation of a map and the ELF relocation of the FD for that map into the bytecode instructions, which would be why you get your error. Typically, when you load a program, several steps occur including:
The loader program (often via libbpf) creates all eBPF maps needed by the eBPF program
Alternatively, it reuses some existing maps. In both cases (existing or new maps), it retrieves a file descriptor for each map (e.g. via their pinned path for existing maps, or returned by the syscall when creating new maps).
Then it inserts this file descriptor into the eBPF bytecode, as an argument to the helper functions used for map access.
At last the loader program loads the updated bytecode into the kernel.
The bytecode goes through the verifier, where the file descriptors are replaced with pointers to the map areas in the kernel memory space.
Your loader is not creating maps (or retrieving FDs for existing, compatible maps), and does not update the bytecode accordingly. So the eBPF program sent to the kernel doesn't say what map it tries to access: we just see, from the verifier logs, 4: (18) r1 = 0x0, where at this stage it should be a memory pointer, such as 4: (18) r1 = 0xffff8ca2c29e3200.
Workarounds
You can obviously extend your loader application to handle maps and ELF relocation. But here are a few other suggestions.
Adding new programs directly amongst the kernel samples is not always ideal. The build system for these samples is rather involved, and relies on a number of header inclusions that are not really standard outside of the kernel repository. On older versions it would also not rely on libbpf but would reimplement most of the loading components, although I think this has improved.
So I would suggest building outside of the kernel repository, if this is not what you have been doing already. In particular, if you're working with C, you should have a look at how libbpf can help handling (loading, attaching, etc.) eBPF programs and other objects.
One of the best starting point would also be libbpf-boostrap, which provides a framework with templates for building eBPF programs and corresponding user space applications very quickly. I would definitely recommend looking at it.
Alternatively, you should be able to load your program with e.g. bpftool prog load <object_file.o> /sys/fs/bpf/<some_path>, although you can't attach it to tracepoints with bpftool only.

Unable to use skb->data with SO_ATTACH_BPF but working with tc [duplicate]

I'm trying to write a simple socket filter eBPF program that can access the socket buffer data.
#include <linux/bpf.h>
#include <linux/if_ether.h>
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("socket_filter")
int myprog(struct __sk_buff *skb) {
void *data = (void *)(long)skb->data;
void *data_end = (void *)(long)skb->data_end;
struct ethhdr *eth = data;
if ((void*)eth + sizeof(*eth) > data_end)
return 0;
return 1;
}
And I'm compiling using clang:
clang -I./ -I/usr/include/x86_64-linux-gnu/asm \
-I/usr/include/x86_64-linux-gnu/ -O2 -target bpf -c test.c -o test.elf
However when I try to load the program I get the following verifier error:
invalid bpf_context access off=80 size=4
My understanding of this error is that it should be thrown when you try to access context data that hasn't been checked to be within data_end, however my code does do that:
Here is the instructions for my program
0000000000000000 packet_counter:
0: 61 12 50 00 00 00 00 00 r2 = *(u32 *)(r1 + 80)
1: 61 11 4c 00 00 00 00 00 r1 = *(u32 *)(r1 + 76)
2: 07 01 00 00 0e 00 00 00 r1 += 14
3: b7 00 00 00 01 00 00 00 r0 = 1
4: 3d 12 01 00 00 00 00 00 if r2 >= r1 goto +1 <LBB0_2>
5: b7 00 00 00 00 00 00 00 r0 = 0
which would imply that the error is being caused by reading the pointer to data_end? However it only happens if I don't try to check the bounds later.
This is because your BPF program is a “socket filter”, and that such programs are not allowed to do direct packet access (see sk_filter_is_valid_access(), where we return false on trying to read skb->data or skb->data_end for example). I do not know the specific reason why it is not available, although I suspect this would be a security precaution as socket filter programs may be available to unprivileged users.
Your program loads just fine as a TC classifier, for example (bpftool prog load foo.o /sys/fs/bpf/foo type classifier -- By the way thanks for the standalone working reproducer, much appreciated!).
If you want to access data for a socket filter, you can still use the bpf_skb_load_bytes() (or bpf_skb_store_bytes()) helper, which automatically does the check on length. Something like this:
#include <linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))
static void *(*bpf_skb_load_bytes)(const struct __sk_buff *, __u32,
void *, __u32) =
(void *) BPF_FUNC_skb_load_bytes;
SEC("socket_filter")
int myprog(struct __sk_buff *skb)
{
__u32 foo;
if (bpf_skb_load_bytes(skb, 0, &foo, sizeof(foo)))
return 0;
if (foo == 3)
return 0;
return 1;
}
Regarding your last comment:
However it only happens if I don't try to check the bounds later.
I suspect clang compiles out the assignments for data and data_end if you do not use them in your code, so they are no longer present and no longer a problem for the verifier.

Error while loading a BPF program that copies a buffer to the BPF stack

I am trying to load a BPF program that simply copies the buf parameter of tty_write to the BPF stack. My program is as follows:
#define BUFSIZE 256
SEC("kprobe/tty_write")
int kprobe__tty_write(struct pt_regs *ctx, struct file *file, const char __user *buf, size_t count)
{
char buffer[BUFSIZE];
bpf_probe_read(buffer, BUFSIZE, (void *)buf);
return 0;
}
Note that I am using bpf_helpers.h from tcptracer-bpf to define the SEC macro. In my real program I would actually use buffer for something, but I have not shown that part here. When I try to load the program (from an ELF file using gobpf) I get the following error:
error while loading "kprobe/tty_write" (permission denied):
0: (bf) r1 = r10
1: (07) r1 += -256
2: (b7) r2 = 256
3: (85) call bpf_probe_read#4
R3 !read_ok
Why is this? My program has been adapted from ttysnoop.py so I know it is possible to do what I'm trying to do. The full disassembly of my program is as follows:
Disassembly of section kprobe/tty_write:
kprobe__tty_write:
0: bf a1 00 00 00 00 00 00 r1 = r10
1: 07 01 00 00 00 ff ff ff r1 += -256
2: b7 02 00 00 00 01 00 00 r2 = 256
3: 85 00 00 00 04 00 00 00 call 4
4: b7 00 00 00 00 00 00 00 r0 = 0
5: 95 00 00 00 00 00 00 00 exit
uname -a:
Linux ubuntu1710 4.13.0-32-generic #35-Ubuntu SMP Thu Jan 25 09:13:46 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
EDIT:
As an experiment, I tried loading a program similar to the example program described when bpf_probe_read_str was introduced as a helper function:
#define BUFSIZE 256
SEC("kprobe/sys_open")
void bpf_sys_open(struct pt_regs *ctx)
{
char buf[BUFSIZE];
bpf_probe_read(buf, sizeof(buf), (void *)ctx->di);
}
Which loads with no issues and gives the following assembly:
Disassembly of section kprobe/sys_open:
bpf_sys_open:
0: 79 13 70 00 00 00 00 00 r3 = *(u64 *)(r1 + 112)
1: bf a1 00 00 00 00 00 00 r1 = r10
2: 07 01 00 00 00 ff ff ff r1 += -256
3: b7 02 00 00 00 01 00 00 r2 = 256
4: 85 00 00 00 04 00 00 00 call 4
5: 95 00 00 00 00 00 00 00 exit
So it seems that my tty_write program is passing the third register straight to the call to bpf_probe_read from when it was set after the kprobe was triggered; this may be the cause of the error I'm seeing, but I am not sure.
As you've discovered yourself, the issue comes from the use of additional parameters to kprobe__tty_write. This works in ttysnoop because it uses bcc to compile and load BPF programs. bcc actually rewrites the additional parameters to the ctx->xx dereferences. You can see this with the following snippet:
from bcc import BPF
BPF(text="""
#include <linux/ptrace.h>
int kprobe__tty_write(struct pt_regs *ctx, struct file *file, const char __user *buf, size_t count) {
return 0;
}
""", debug=4)
Thanks to debug=4, we can see the rewrites when executing:
$ sudo python tmp.py
clang -cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -emit-llvm-uselists -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.c -mrelocation-model static -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu x86-64 -momit-leaf-frame-pointer -dwarf-column-info -debugger-tuning=gdb -coverage-notes-file /usr/src/linux-headers-4.4.0-112-generic/main.gcno -nostdsysteminc -nobuiltininc -resource-dir lib/clang/5.0.1 -isystem /virtual/lib/clang/include -include ./include/linux/kconfig.h -include /virtual/include/bcc/bpf.h -include /virtual/include/bcc/helpers.h -isystem /virtual/include -I /home/paul/bcc2 -I ./arch/x86/include -I arch/x86/include/generated/uapi -I arch/x86/include/generated -I include -I ./arch/x86/include/uapi -I arch/x86/include/generated/uapi -I ./include/uapi -I include/generated/uapi -D __KERNEL__ -D __HAVE_BUILTIN_BSWAP16__ -D __HAVE_BUILTIN_BSWAP32__ -D __HAVE_BUILTIN_BSWAP64__ -O2 -Wno-deprecated-declarations -Wno-gnu-variable-sized-type-not-at-end -Wno-pragma-once-outside-header -Wno-address-of-packed-member -Wno-unknown-warning-option -Wno-unused-value -Wno-pointer-sign -fdebug-compilation-dir /usr/src/linux-headers-4.4.0-112-generic -ferror-limit 19 -fmessage-length 168 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -o main.bc -x c /virtual/main.c
#include <linux/ptrace.h>
__attribute__((section(".bpf.fn.kprobe__tty_write")))
int kprobe__tty_write(struct pt_regs *ctx) { struct file *file = ctx->di; const char __user *buf = ctx->si; size_t count = ctx->dx;
return 0;
}
In the same manner, bcc extract the function name from kprobe__tty_write and automagically attaches the BPF program to tty_write.

How can I find the **type** or **length** information in the .data section dump file?

Test platform is on 32 bit Linux.
Here is my code:
#include <stdio.h>
#include "calc_mean.h"
extern double mean(double, double);
extern int aaaa;
static int b;
static int c = 999999999;
static double d;
static float e = 2.0;
static double f = 2.0;
int main(int argc, char* argv[]) {
double v1, v2, m;
v1 = 5.2;
v2 = 7.9;
aaaa = 100;
b = 123;
c = 321;
d = 13.3;
e = 122.2;
e = 123123.123;
f = 11231233.0;
f = 111233.0;
f = 1133.0;
f = 11231231231233.0;
e = 33.4;
printf("%d\n", aaaa);
printf("asdfjkhadsfkjhadskfjh\n");
printf("adsjfhaskdjfhakjdshfkajhdsfkjahdfkjh%d\n", aaaa);
m = mean(v1, v2);
printf("The mean of %3.2f and %3.2f is %3.2f\n", v1, v2, m);
return 0;
}
I use objdump to dump the .data section's content, and here are the info I got.
objdump -s -j .data test
dump info
test: file format elf32-i386
Contents of section .data:
804a018 00000000 00000000 ffc99a3b 00000040 ...........;...#
804a028 00000000 00000040 .......#
Then another method:
objdump -D test > dump
here is the .data section in dump
Disassembly of section .data:
0804a018 <__data_start>:
804a018: 00 00 add %al,(%eax)
...
0804a01c <__dso_handle>:
804a01c: 00 00 add %al,(%eax)
...
0804a020 <c>:
804a020: ff c9 dec %ecx
804a022: 9a 3b 00 00 00 40 00 lcall $0x40,$0x3b
0804a024 <e>:
804a024: 00 00 add %al,(%eax)
804a026: 00 40 00 add %al,0x0(%eax)
0804a028 <f>:
804a028: 00 00 add %al,(%eax)
804a02a: 00 00 add %al,(%eax)
804a02c: 00 00 add %al,(%eax)
804a02e: 00 .byte 0x0
804a02f: 40 inc %eax
So what I am trying to do is obtaining the variable info(like variable name, length, value) from the dump(and probably with disassembly) info I present
But currently I don't know how to obtain the type info from the dump file, and I think without the type information, I can hardly know the length as well as value of each variable...
Could anyone give me some help?
THank you!
Variable information such as variable name, address, size etc. is usually compiled as DWARF information in the executable. It will only be available when you compile your code with -g flag. Look for section names starting with .dwarf when using objdump or similar tools.

Resources