首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >bpf_trace_printk导致内核-libbpf中未加载的程序:程序'xdp‘包含指向第6节的未识别的关系数据。

bpf_trace_printk导致内核-libbpf中未加载的程序:程序'xdp‘包含指向第6节的未识别的关系数据。
EN

Stack Overflow用户
提问于 2022-08-24 11:07:49
回答 1查看 146关注 0票数 0

下面是我的代码和libbpf抛出的错误

代码语言:javascript
复制
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

为什么会这样呢。我就是这样用bpf_trace_printk打印的

代码语言:javascript
复制
      bpf_trace_printk("hello\n",sizeof("hello\n"));

这是完整的代码

代码语言:javascript
复制
#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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-24 21:26:29

TL;DR

不要这样称呼你的帮手:

代码语言:javascript
复制
    // BAD
    bpf_trace_printk("hello\n", sizeof("hello\n"));

或者像这样:

代码语言:javascript
复制
    // BAD
    const char *msg = "hello\n";
    bpf_trace_printk(msg, sizeof("hello\n"));

但是,将您的字符串声明为一个动态的字符数组:

代码语言:javascript
复制
    // GOOD
    char msg[] = "hello\n";
    bpf_trace_printk(msg, sizeof(msg));

这将防止clang创建libbpf无法处理的重新定位。

解释

让我们看看对象文件,当直接传递字符串时:

代码语言:javascript
复制
#include <linux/bpf.h>
#include "bpf_helper_defs.h"

int foo(void)
{
    bpf_trace_printk("hello\n", sizeof("hello\n"));
    return 0;
}

执行此操作时,clang将字符串放入只读部分,并请求重新定位。我们可以用llvm-objdump观察到这一点。让我们检查重新定位并拆卸程序:

代码语言:javascript
复制
$ 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

我们注意到,包含程序的.text部分以单个load r1 = 0开头:寄存器r1包含传递给调用bpf_trace_printk() (call 6)的第一个参数,直到这种重定位发生时才设置。

但是libbpf不支持这种重定位,这就是您获得错误消息的原因:

代码语言:javascript
复制
Program 'xdp' contains unrecognized relo data pointing to section 6

在以下方面也可以看到这一点:

代码语言:javascript
复制
#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;
}

这是等价的,clang也创造了一个重新安置。

但是,我们可以将字符串声明为一个动态的字符数组:

代码语言:javascript
复制
#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;
}

在这种情况下,数组进入堆栈。不发生搬迁。文件中不存在.rodata.str1.1部分。我们可以检查llvm-objdump说了什么:

代码语言:javascript
复制
$ 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

在这里,我们用字符串的字符填充堆栈(r10是堆栈指针) (68 65 6c 6c 6f 0a 00 00hello\n\0\0)。每件事都是在BPF处理的,不涉及搬迁。而且这个很好用。

我们能做得更好吗?是的,对于Linux5.2和更高版本,我们可以通过将字符串声明为:

代码语言:javascript
复制
    static const char msg[] = "hello\n";

这一次,这将导致重新定位到节.rodata,但是libbpf通过对静态变量的支持来处理这个部分。更多详细信息可获得这里

一般来说,https://nakryiko.com/posts/bpf-tips-printk/bpf_trace_printk()助手的一个极好的参考。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73472044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档