mirror of
https://github.com/netdata/libbpf.git
synced 2026-04-01 06:09:06 +08:00
sync with latest bpf-next (#6)
The following two new files are added: README.rst bpf_prog_linfo.c Signed-off-by: Yonghong Song <yhs@fb.com>
This commit is contained in:
@@ -133,6 +133,14 @@ enum bpf_map_type {
|
|||||||
BPF_MAP_TYPE_STACK,
|
BPF_MAP_TYPE_STACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Note that tracing related programs such as
|
||||||
|
* BPF_PROG_TYPE_{KPROBE,TRACEPOINT,PERF_EVENT,RAW_TRACEPOINT}
|
||||||
|
* are not subject to a stable API since kernel internal data
|
||||||
|
* structures can change from release to release and may
|
||||||
|
* therefore break existing tracing BPF programs. Tracing BPF
|
||||||
|
* programs correspond to /a/ specific kernel which is to be
|
||||||
|
* analyzed, and not /a/ specific kernel /and/ all future ones.
|
||||||
|
*/
|
||||||
enum bpf_prog_type {
|
enum bpf_prog_type {
|
||||||
BPF_PROG_TYPE_UNSPEC,
|
BPF_PROG_TYPE_UNSPEC,
|
||||||
BPF_PROG_TYPE_SOCKET_FILTER,
|
BPF_PROG_TYPE_SOCKET_FILTER,
|
||||||
@@ -232,6 +240,20 @@ enum bpf_attach_type {
|
|||||||
*/
|
*/
|
||||||
#define BPF_F_STRICT_ALIGNMENT (1U << 0)
|
#define BPF_F_STRICT_ALIGNMENT (1U << 0)
|
||||||
|
|
||||||
|
/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
|
||||||
|
* verifier will allow any alignment whatsoever. On platforms
|
||||||
|
* with strict alignment requirements for loads ands stores (such
|
||||||
|
* as sparc and mips) the verifier validates that all loads and
|
||||||
|
* stores provably follow this requirement. This flag turns that
|
||||||
|
* checking and enforcement off.
|
||||||
|
*
|
||||||
|
* It is mostly used for testing when we want to validate the
|
||||||
|
* context and memory access aspects of the verifier, but because
|
||||||
|
* of an unaligned access the alignment check would trigger before
|
||||||
|
* the one we are interested in.
|
||||||
|
*/
|
||||||
|
#define BPF_F_ANY_ALIGNMENT (1U << 1)
|
||||||
|
|
||||||
/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
|
/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */
|
||||||
#define BPF_PSEUDO_MAP_FD 1
|
#define BPF_PSEUDO_MAP_FD 1
|
||||||
|
|
||||||
@@ -329,7 +351,7 @@ union bpf_attr {
|
|||||||
__u32 log_level; /* verbosity level of verifier */
|
__u32 log_level; /* verbosity level of verifier */
|
||||||
__u32 log_size; /* size of user buffer */
|
__u32 log_size; /* size of user buffer */
|
||||||
__aligned_u64 log_buf; /* user supplied buffer */
|
__aligned_u64 log_buf; /* user supplied buffer */
|
||||||
__u32 kern_version; /* checked when prog_type=kprobe */
|
__u32 kern_version; /* not used */
|
||||||
__u32 prog_flags;
|
__u32 prog_flags;
|
||||||
char prog_name[BPF_OBJ_NAME_LEN];
|
char prog_name[BPF_OBJ_NAME_LEN];
|
||||||
__u32 prog_ifindex; /* ifindex of netdev to prep for */
|
__u32 prog_ifindex; /* ifindex of netdev to prep for */
|
||||||
@@ -342,6 +364,9 @@ union bpf_attr {
|
|||||||
__u32 func_info_rec_size; /* userspace bpf_func_info size */
|
__u32 func_info_rec_size; /* userspace bpf_func_info size */
|
||||||
__aligned_u64 func_info; /* func info */
|
__aligned_u64 func_info; /* func info */
|
||||||
__u32 func_info_cnt; /* number of bpf_func_info records */
|
__u32 func_info_cnt; /* number of bpf_func_info records */
|
||||||
|
__u32 line_info_rec_size; /* userspace bpf_line_info size */
|
||||||
|
__aligned_u64 line_info; /* line info */
|
||||||
|
__u32 line_info_cnt; /* number of bpf_line_info records */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||||
@@ -360,8 +385,11 @@ union bpf_attr {
|
|||||||
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
|
||||||
__u32 prog_fd;
|
__u32 prog_fd;
|
||||||
__u32 retval;
|
__u32 retval;
|
||||||
__u32 data_size_in;
|
__u32 data_size_in; /* input: len of data_in */
|
||||||
__u32 data_size_out;
|
__u32 data_size_out; /* input/output: len of data_out
|
||||||
|
* returns ENOSPC if data_out
|
||||||
|
* is too small.
|
||||||
|
*/
|
||||||
__aligned_u64 data_in;
|
__aligned_u64 data_in;
|
||||||
__aligned_u64 data_out;
|
__aligned_u64 data_out;
|
||||||
__u32 repeat;
|
__u32 repeat;
|
||||||
@@ -482,18 +510,6 @@ union bpf_attr {
|
|||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* int bpf_map_pop_elem(struct bpf_map *map, void *value)
|
|
||||||
* Description
|
|
||||||
* Pop an element from *map*.
|
|
||||||
* Return
|
|
||||||
* 0 on success, or a negative error in case of failure.
|
|
||||||
*
|
|
||||||
* int bpf_map_peek_elem(struct bpf_map *map, void *value)
|
|
||||||
* Description
|
|
||||||
* Get an element from *map* without removing it.
|
|
||||||
* Return
|
|
||||||
* 0 on success, or a negative error in case of failure.
|
|
||||||
*
|
|
||||||
* int bpf_probe_read(void *dst, u32 size, const void *src)
|
* int bpf_probe_read(void *dst, u32 size, const void *src)
|
||||||
* Description
|
* Description
|
||||||
* For tracing programs, safely attempt to read *size* bytes from
|
* For tracing programs, safely attempt to read *size* bytes from
|
||||||
@@ -1917,9 +1933,9 @@ union bpf_attr {
|
|||||||
* is set to metric from route (IPv4/IPv6 only), and ifindex
|
* is set to metric from route (IPv4/IPv6 only), and ifindex
|
||||||
* is set to the device index of the nexthop from the FIB lookup.
|
* is set to the device index of the nexthop from the FIB lookup.
|
||||||
*
|
*
|
||||||
* *plen* argument is the size of the passed in struct.
|
* *plen* argument is the size of the passed in struct.
|
||||||
* *flags* argument can be a combination of one or more of the
|
* *flags* argument can be a combination of one or more of the
|
||||||
* following values:
|
* following values:
|
||||||
*
|
*
|
||||||
* **BPF_FIB_LOOKUP_DIRECT**
|
* **BPF_FIB_LOOKUP_DIRECT**
|
||||||
* Do a direct table lookup vs full lookup using FIB
|
* Do a direct table lookup vs full lookup using FIB
|
||||||
@@ -1928,9 +1944,9 @@ union bpf_attr {
|
|||||||
* Perform lookup from an egress perspective (default is
|
* Perform lookup from an egress perspective (default is
|
||||||
* ingress).
|
* ingress).
|
||||||
*
|
*
|
||||||
* *ctx* is either **struct xdp_md** for XDP programs or
|
* *ctx* is either **struct xdp_md** for XDP programs or
|
||||||
* **struct sk_buff** tc cls_act programs.
|
* **struct sk_buff** tc cls_act programs.
|
||||||
* Return
|
* Return
|
||||||
* * < 0 if any input argument is invalid
|
* * < 0 if any input argument is invalid
|
||||||
* * 0 on success (packet is forwarded, nexthop neighbor exists)
|
* * 0 on success (packet is forwarded, nexthop neighbor exists)
|
||||||
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
* * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
|
||||||
@@ -2075,8 +2091,8 @@ union bpf_attr {
|
|||||||
* translated to a keycode using the rc keymap, and reported as
|
* translated to a keycode using the rc keymap, and reported as
|
||||||
* an input key down event. After a period a key up event is
|
* an input key down event. After a period a key up event is
|
||||||
* generated. This period can be extended by calling either
|
* generated. This period can be extended by calling either
|
||||||
* **bpf_rc_keydown** () again with the same values, or calling
|
* **bpf_rc_keydown**\ () again with the same values, or calling
|
||||||
* **bpf_rc_repeat** ().
|
* **bpf_rc_repeat**\ ().
|
||||||
*
|
*
|
||||||
* Some protocols include a toggle bit, in case the button was
|
* Some protocols include a toggle bit, in case the button was
|
||||||
* released and pressed again between consecutive scancodes.
|
* released and pressed again between consecutive scancodes.
|
||||||
@@ -2159,29 +2175,30 @@ union bpf_attr {
|
|||||||
* The *flags* meaning is specific for each map type,
|
* The *flags* meaning is specific for each map type,
|
||||||
* and has to be 0 for cgroup local storage.
|
* and has to be 0 for cgroup local storage.
|
||||||
*
|
*
|
||||||
* Depending on the bpf program type, a local storage area
|
* Depending on the BPF program type, a local storage area
|
||||||
* can be shared between multiple instances of the bpf program,
|
* can be shared between multiple instances of the BPF program,
|
||||||
* running simultaneously.
|
* running simultaneously.
|
||||||
*
|
*
|
||||||
* A user should care about the synchronization by himself.
|
* A user should care about the synchronization by himself.
|
||||||
* For example, by using the BPF_STX_XADD instruction to alter
|
* For example, by using the **BPF_STX_XADD** instruction to alter
|
||||||
* the shared data.
|
* the shared data.
|
||||||
* Return
|
* Return
|
||||||
* Pointer to the local storage area.
|
* A pointer to the local storage area.
|
||||||
*
|
*
|
||||||
* int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
|
* int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Select a SO_REUSEPORT sk from a BPF_MAP_TYPE_REUSEPORT_ARRAY map
|
* Select a **SO_REUSEPORT** socket from a
|
||||||
* It checks the selected sk is matching the incoming
|
* **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*.
|
||||||
* request in the skb.
|
* It checks the selected socket is matching the incoming
|
||||||
|
* request in the socket buffer.
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
* struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags)
|
* struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Look for TCP socket matching *tuple*, optionally in a child
|
* Look for TCP socket matching *tuple*, optionally in a child
|
||||||
* network namespace *netns*. The return value must be checked,
|
* network namespace *netns*. The return value must be checked,
|
||||||
* and if non-NULL, released via **bpf_sk_release**\ ().
|
* and if non-**NULL**, released via **bpf_sk_release**\ ().
|
||||||
*
|
*
|
||||||
* The *ctx* should point to the context of the program, such as
|
* The *ctx* should point to the context of the program, such as
|
||||||
* the skb or socket (depending on the hook in use). This is used
|
* the skb or socket (depending on the hook in use). This is used
|
||||||
@@ -2194,12 +2211,14 @@ union bpf_attr {
|
|||||||
* **sizeof**\ (*tuple*\ **->ipv6**)
|
* **sizeof**\ (*tuple*\ **->ipv6**)
|
||||||
* Look for an IPv6 socket.
|
* Look for an IPv6 socket.
|
||||||
*
|
*
|
||||||
* If the *netns* is zero, then the socket lookup table in the
|
* If the *netns* is a negative signed 32-bit integer, then the
|
||||||
* netns associated with the *ctx* will be used. For the TC hooks,
|
* socket lookup table in the netns associated with the *ctx* will
|
||||||
* this in the netns of the device in the skb. For socket hooks,
|
* will be used. For the TC hooks, this is the netns of the device
|
||||||
* this in the netns of the socket. If *netns* is non-zero, then
|
* in the skb. For socket hooks, this is the netns of the socket.
|
||||||
* it specifies the ID of the netns relative to the netns
|
* If *netns* is any other signed 32-bit value greater than or
|
||||||
* associated with the *ctx*.
|
* equal to zero then it specifies the ID of the netns relative to
|
||||||
|
* the netns associated with the *ctx*. *netns* values beyond the
|
||||||
|
* range of 32-bit integers are reserved for future use.
|
||||||
*
|
*
|
||||||
* All values for *flags* are reserved for future usage, and must
|
* All values for *flags* are reserved for future usage, and must
|
||||||
* be left at zero.
|
* be left at zero.
|
||||||
@@ -2207,15 +2226,15 @@ union bpf_attr {
|
|||||||
* This helper is available only if the kernel was compiled with
|
* This helper is available only if the kernel was compiled with
|
||||||
* **CONFIG_NET** configuration option.
|
* **CONFIG_NET** configuration option.
|
||||||
* Return
|
* Return
|
||||||
* Pointer to *struct bpf_sock*, or NULL in case of failure.
|
* Pointer to **struct bpf_sock**, or **NULL** in case of failure.
|
||||||
* For sockets with reuseport option, *struct bpf_sock*
|
* For sockets with reuseport option, the **struct bpf_sock**
|
||||||
* return is from reuse->socks[] using hash of the packet.
|
* result is from **reuse->socks**\ [] using the hash of the tuple.
|
||||||
*
|
*
|
||||||
* struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u32 netns, u64 flags)
|
* struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* Look for UDP socket matching *tuple*, optionally in a child
|
* Look for UDP socket matching *tuple*, optionally in a child
|
||||||
* network namespace *netns*. The return value must be checked,
|
* network namespace *netns*. The return value must be checked,
|
||||||
* and if non-NULL, released via **bpf_sk_release**\ ().
|
* and if non-**NULL**, released via **bpf_sk_release**\ ().
|
||||||
*
|
*
|
||||||
* The *ctx* should point to the context of the program, such as
|
* The *ctx* should point to the context of the program, such as
|
||||||
* the skb or socket (depending on the hook in use). This is used
|
* the skb or socket (depending on the hook in use). This is used
|
||||||
@@ -2228,12 +2247,14 @@ union bpf_attr {
|
|||||||
* **sizeof**\ (*tuple*\ **->ipv6**)
|
* **sizeof**\ (*tuple*\ **->ipv6**)
|
||||||
* Look for an IPv6 socket.
|
* Look for an IPv6 socket.
|
||||||
*
|
*
|
||||||
* If the *netns* is zero, then the socket lookup table in the
|
* If the *netns* is a negative signed 32-bit integer, then the
|
||||||
* netns associated with the *ctx* will be used. For the TC hooks,
|
* socket lookup table in the netns associated with the *ctx* will
|
||||||
* this in the netns of the device in the skb. For socket hooks,
|
* will be used. For the TC hooks, this is the netns of the device
|
||||||
* this in the netns of the socket. If *netns* is non-zero, then
|
* in the skb. For socket hooks, this is the netns of the socket.
|
||||||
* it specifies the ID of the netns relative to the netns
|
* If *netns* is any other signed 32-bit value greater than or
|
||||||
* associated with the *ctx*.
|
* equal to zero then it specifies the ID of the netns relative to
|
||||||
|
* the netns associated with the *ctx*. *netns* values beyond the
|
||||||
|
* range of 32-bit integers are reserved for future use.
|
||||||
*
|
*
|
||||||
* All values for *flags* are reserved for future usage, and must
|
* All values for *flags* are reserved for future usage, and must
|
||||||
* be left at zero.
|
* be left at zero.
|
||||||
@@ -2241,33 +2262,71 @@ union bpf_attr {
|
|||||||
* This helper is available only if the kernel was compiled with
|
* This helper is available only if the kernel was compiled with
|
||||||
* **CONFIG_NET** configuration option.
|
* **CONFIG_NET** configuration option.
|
||||||
* Return
|
* Return
|
||||||
* Pointer to *struct bpf_sock*, or NULL in case of failure.
|
* Pointer to **struct bpf_sock**, or **NULL** in case of failure.
|
||||||
* For sockets with reuseport option, *struct bpf_sock*
|
* For sockets with reuseport option, the **struct bpf_sock**
|
||||||
* return is from reuse->socks[] using hash of the packet.
|
* result is from **reuse->socks**\ [] using the hash of the tuple.
|
||||||
*
|
*
|
||||||
* int bpf_sk_release(struct bpf_sock *sk)
|
* int bpf_sk_release(struct bpf_sock *sock)
|
||||||
* Description
|
* Description
|
||||||
* Release the reference held by *sock*. *sock* must be a non-NULL
|
* Release the reference held by *sock*. *sock* must be a
|
||||||
* pointer that was returned from bpf_sk_lookup_xxx\ ().
|
* non-**NULL** pointer that was returned from
|
||||||
|
* **bpf_sk_lookup_xxx**\ ().
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
*
|
*
|
||||||
|
* int bpf_map_pop_elem(struct bpf_map *map, void *value)
|
||||||
|
* Description
|
||||||
|
* Pop an element from *map*.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_map_peek_elem(struct bpf_map *map, void *value)
|
||||||
|
* Description
|
||||||
|
* Get an element from *map* without removing it.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
* int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags)
|
* int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags)
|
||||||
* Description
|
* Description
|
||||||
* For socket policies, insert *len* bytes into msg at offset
|
* For socket policies, insert *len* bytes into *msg* at offset
|
||||||
* *start*.
|
* *start*.
|
||||||
*
|
*
|
||||||
* If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a
|
* If a program of type **BPF_PROG_TYPE_SK_MSG** is run on a
|
||||||
* *msg* it may want to insert metadata or options into the msg.
|
* *msg* it may want to insert metadata or options into the *msg*.
|
||||||
* This can later be read and used by any of the lower layer BPF
|
* This can later be read and used by any of the lower layer BPF
|
||||||
* hooks.
|
* hooks.
|
||||||
*
|
*
|
||||||
* This helper may fail if under memory pressure (a malloc
|
* This helper may fail if under memory pressure (a malloc
|
||||||
* fails) in these cases BPF programs will get an appropriate
|
* fails) in these cases BPF programs will get an appropriate
|
||||||
* error and BPF programs will need to handle them.
|
* error and BPF programs will need to handle them.
|
||||||
*
|
|
||||||
* Return
|
* Return
|
||||||
* 0 on success, or a negative error in case of failure.
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 pop, u64 flags)
|
||||||
|
* Description
|
||||||
|
* Will remove *pop* bytes from a *msg* starting at byte *start*.
|
||||||
|
* This may result in **ENOMEM** errors under certain situations if
|
||||||
|
* an allocation and copy are required due to a full ring buffer.
|
||||||
|
* However, the helper will try to avoid doing the allocation
|
||||||
|
* if possible. Other errors can occur if input parameters are
|
||||||
|
* invalid either due to *start* byte not being valid part of *msg*
|
||||||
|
* payload and/or *pop* value being to large.
|
||||||
|
* Return
|
||||||
|
* 0 on success, or a negative error in case of failure.
|
||||||
|
*
|
||||||
|
* int bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y)
|
||||||
|
* Description
|
||||||
|
* This helper is used in programs implementing IR decoding, to
|
||||||
|
* report a successfully decoded pointer movement.
|
||||||
|
*
|
||||||
|
* The *ctx* should point to the lirc sample as passed into
|
||||||
|
* the program.
|
||||||
|
*
|
||||||
|
* This helper is only available is the kernel was compiled with
|
||||||
|
* the **CONFIG_BPF_LIRC_MODE2** configuration option set to
|
||||||
|
* "**y**".
|
||||||
|
* Return
|
||||||
|
* 0
|
||||||
*/
|
*/
|
||||||
#define __BPF_FUNC_MAPPER(FN) \
|
#define __BPF_FUNC_MAPPER(FN) \
|
||||||
FN(unspec), \
|
FN(unspec), \
|
||||||
@@ -2360,7 +2419,9 @@ union bpf_attr {
|
|||||||
FN(map_push_elem), \
|
FN(map_push_elem), \
|
||||||
FN(map_pop_elem), \
|
FN(map_pop_elem), \
|
||||||
FN(map_peek_elem), \
|
FN(map_peek_elem), \
|
||||||
FN(msg_push_data),
|
FN(msg_push_data), \
|
||||||
|
FN(msg_pop_data), \
|
||||||
|
FN(rc_pointer_rel),
|
||||||
|
|
||||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||||
* function eBPF program intends to call
|
* function eBPF program intends to call
|
||||||
@@ -2416,6 +2477,9 @@ enum bpf_func_id {
|
|||||||
/* BPF_FUNC_perf_event_output for sk_buff input context. */
|
/* BPF_FUNC_perf_event_output for sk_buff input context. */
|
||||||
#define BPF_F_CTXLEN_MASK (0xfffffULL << 32)
|
#define BPF_F_CTXLEN_MASK (0xfffffULL << 32)
|
||||||
|
|
||||||
|
/* Current network namespace */
|
||||||
|
#define BPF_F_CURRENT_NETNS (-1L)
|
||||||
|
|
||||||
/* Mode for BPF_FUNC_skb_adjust_room helper. */
|
/* Mode for BPF_FUNC_skb_adjust_room helper. */
|
||||||
enum bpf_adj_room_mode {
|
enum bpf_adj_room_mode {
|
||||||
BPF_ADJ_ROOM_NET,
|
BPF_ADJ_ROOM_NET,
|
||||||
@@ -2433,6 +2497,12 @@ enum bpf_lwt_encap_mode {
|
|||||||
BPF_LWT_ENCAP_SEG6_INLINE
|
BPF_LWT_ENCAP_SEG6_INLINE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define __bpf_md_ptr(type, name) \
|
||||||
|
union { \
|
||||||
|
type name; \
|
||||||
|
__u64 :64; \
|
||||||
|
} __attribute__((aligned(8)))
|
||||||
|
|
||||||
/* user accessible mirror of in-kernel sk_buff.
|
/* user accessible mirror of in-kernel sk_buff.
|
||||||
* new fields can only be added to the end of this structure
|
* new fields can only be added to the end of this structure
|
||||||
*/
|
*/
|
||||||
@@ -2467,8 +2537,9 @@ struct __sk_buff {
|
|||||||
/* ... here. */
|
/* ... here. */
|
||||||
|
|
||||||
__u32 data_meta;
|
__u32 data_meta;
|
||||||
struct bpf_flow_keys *flow_keys;
|
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
|
||||||
__u64 tstamp;
|
__u64 tstamp;
|
||||||
|
__u32 wire_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_tunnel_key {
|
struct bpf_tunnel_key {
|
||||||
@@ -2584,8 +2655,8 @@ enum sk_action {
|
|||||||
* be added to the end of this structure
|
* be added to the end of this structure
|
||||||
*/
|
*/
|
||||||
struct sk_msg_md {
|
struct sk_msg_md {
|
||||||
void *data;
|
__bpf_md_ptr(void *, data);
|
||||||
void *data_end;
|
__bpf_md_ptr(void *, data_end);
|
||||||
|
|
||||||
__u32 family;
|
__u32 family;
|
||||||
__u32 remote_ip4; /* Stored in network byte order */
|
__u32 remote_ip4; /* Stored in network byte order */
|
||||||
@@ -2594,6 +2665,7 @@ struct sk_msg_md {
|
|||||||
__u32 local_ip6[4]; /* Stored in network byte order */
|
__u32 local_ip6[4]; /* Stored in network byte order */
|
||||||
__u32 remote_port; /* Stored in network byte order */
|
__u32 remote_port; /* Stored in network byte order */
|
||||||
__u32 local_port; /* stored in host byte order */
|
__u32 local_port; /* stored in host byte order */
|
||||||
|
__u32 size; /* Total size of sk_msg */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sk_reuseport_md {
|
struct sk_reuseport_md {
|
||||||
@@ -2601,8 +2673,9 @@ struct sk_reuseport_md {
|
|||||||
* Start of directly accessible data. It begins from
|
* Start of directly accessible data. It begins from
|
||||||
* the tcp/udp header.
|
* the tcp/udp header.
|
||||||
*/
|
*/
|
||||||
void *data;
|
__bpf_md_ptr(void *, data);
|
||||||
void *data_end; /* End of directly accessible data */
|
/* End of directly accessible data */
|
||||||
|
__bpf_md_ptr(void *, data_end);
|
||||||
/*
|
/*
|
||||||
* Total length of packet (starting from the tcp/udp header).
|
* Total length of packet (starting from the tcp/udp header).
|
||||||
* Note that the directly accessible bytes (data_end - data)
|
* Note that the directly accessible bytes (data_end - data)
|
||||||
@@ -2646,7 +2719,15 @@ struct bpf_prog_info {
|
|||||||
__u32 btf_id;
|
__u32 btf_id;
|
||||||
__u32 func_info_rec_size;
|
__u32 func_info_rec_size;
|
||||||
__aligned_u64 func_info;
|
__aligned_u64 func_info;
|
||||||
__u32 func_info_cnt;
|
__u32 nr_func_info;
|
||||||
|
__u32 nr_line_info;
|
||||||
|
__aligned_u64 line_info;
|
||||||
|
__aligned_u64 jited_line_info;
|
||||||
|
__u32 nr_jited_line_info;
|
||||||
|
__u32 line_info_rec_size;
|
||||||
|
__u32 jited_line_info_rec_size;
|
||||||
|
__u32 nr_prog_tags;
|
||||||
|
__aligned_u64 prog_tags;
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
struct bpf_map_info {
|
struct bpf_map_info {
|
||||||
@@ -2959,8 +3040,18 @@ struct bpf_flow_keys {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_func_info {
|
struct bpf_func_info {
|
||||||
__u32 insn_offset;
|
__u32 insn_off;
|
||||||
__u32 type_id;
|
__u32 type_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BPF_LINE_INFO_LINE_NUM(line_col) ((line_col) >> 10)
|
||||||
|
#define BPF_LINE_INFO_LINE_COL(line_col) ((line_col) & 0x3ff)
|
||||||
|
|
||||||
|
struct bpf_line_info {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 file_name_off;
|
||||||
|
__u32 line_off;
|
||||||
|
__u32 line_col;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _UAPI__LINUX_BPF_H__ */
|
#endif /* _UAPI__LINUX_BPF_H__ */
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ struct btf_type {
|
|||||||
* bits 0-15: vlen (e.g. # of struct's members)
|
* bits 0-15: vlen (e.g. # of struct's members)
|
||||||
* bits 16-23: unused
|
* bits 16-23: unused
|
||||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||||
* bits 28-31: unused
|
* bits 28-30: unused
|
||||||
|
* bit 31: kind_flag, currently used by
|
||||||
|
* struct, union and fwd
|
||||||
*/
|
*/
|
||||||
__u32 info;
|
__u32 info;
|
||||||
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
/* "size" is used by INT, ENUM, STRUCT and UNION.
|
||||||
@@ -52,6 +54,7 @@ struct btf_type {
|
|||||||
|
|
||||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
||||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||||
|
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||||
|
|
||||||
#define BTF_KIND_UNKN 0 /* Unknown */
|
#define BTF_KIND_UNKN 0 /* Unknown */
|
||||||
#define BTF_KIND_INT 1 /* Integer */
|
#define BTF_KIND_INT 1 /* Integer */
|
||||||
@@ -110,9 +113,22 @@ struct btf_array {
|
|||||||
struct btf_member {
|
struct btf_member {
|
||||||
__u32 name_off;
|
__u32 name_off;
|
||||||
__u32 type;
|
__u32 type;
|
||||||
__u32 offset; /* offset in bits */
|
/* If the type info kind_flag is set, the btf_member offset
|
||||||
|
* contains both member bitfield size and bit offset. The
|
||||||
|
* bitfield size is set for bitfield members. If the type
|
||||||
|
* info kind_flag is not set, the offset contains only bit
|
||||||
|
* offset.
|
||||||
|
*/
|
||||||
|
__u32 offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* If the struct/union type info kind_flag is set, the
|
||||||
|
* following two macros are used to access bitfield_size
|
||||||
|
* and bit_offset from btf_member.offset.
|
||||||
|
*/
|
||||||
|
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
|
||||||
|
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
|
||||||
|
|
||||||
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
|
||||||
* The exact number of btf_param is stored in the vlen (of the
|
* The exact number of btf_param is stored in the vlen (of the
|
||||||
* info in "struct btf_type").
|
* info in "struct btf_type").
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ enum nlmsgerr_attrs {
|
|||||||
#define NETLINK_LIST_MEMBERSHIPS 9
|
#define NETLINK_LIST_MEMBERSHIPS 9
|
||||||
#define NETLINK_CAP_ACK 10
|
#define NETLINK_CAP_ACK 10
|
||||||
#define NETLINK_EXT_ACK 11
|
#define NETLINK_EXT_ACK 11
|
||||||
#define NETLINK_DUMP_STRICT_CHK 12
|
#define NETLINK_GET_STRICT_CHK 12
|
||||||
|
|
||||||
struct nl_pktinfo {
|
struct nl_pktinfo {
|
||||||
__u32 group;
|
__u32 group;
|
||||||
|
|||||||
139
src/README.rst
Normal file
139
src/README.rst
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
libbpf API naming convention
|
||||||
|
============================
|
||||||
|
|
||||||
|
libbpf API provides access to a few logically separated groups of
|
||||||
|
functions and types. Every group has its own naming convention
|
||||||
|
described here. It's recommended to follow these conventions whenever a
|
||||||
|
new function or type is added to keep libbpf API clean and consistent.
|
||||||
|
|
||||||
|
All types and functions provided by libbpf API should have one of the
|
||||||
|
following prefixes: ``bpf_``, ``btf_``, ``libbpf_``.
|
||||||
|
|
||||||
|
System call wrappers
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
System call wrappers are simple wrappers for commands supported by
|
||||||
|
sys_bpf system call. These wrappers should go to ``bpf.h`` header file
|
||||||
|
and map one-on-one to corresponding commands.
|
||||||
|
|
||||||
|
For example ``bpf_map_lookup_elem`` wraps ``BPF_MAP_LOOKUP_ELEM``
|
||||||
|
command of sys_bpf, ``bpf_prog_attach`` wraps ``BPF_PROG_ATTACH``, etc.
|
||||||
|
|
||||||
|
Objects
|
||||||
|
-------
|
||||||
|
|
||||||
|
Another class of types and functions provided by libbpf API is "objects"
|
||||||
|
and functions to work with them. Objects are high-level abstractions
|
||||||
|
such as BPF program or BPF map. They're represented by corresponding
|
||||||
|
structures such as ``struct bpf_object``, ``struct bpf_program``,
|
||||||
|
``struct bpf_map``, etc.
|
||||||
|
|
||||||
|
Structures are forward declared and access to their fields should be
|
||||||
|
provided via corresponding getters and setters rather than directly.
|
||||||
|
|
||||||
|
These objects are associated with corresponding parts of ELF object that
|
||||||
|
contains compiled BPF programs.
|
||||||
|
|
||||||
|
For example ``struct bpf_object`` represents ELF object itself created
|
||||||
|
from an ELF file or from a buffer, ``struct bpf_program`` represents a
|
||||||
|
program in ELF object and ``struct bpf_map`` is a map.
|
||||||
|
|
||||||
|
Functions that work with an object have names built from object name,
|
||||||
|
double underscore and part that describes function purpose.
|
||||||
|
|
||||||
|
For example ``bpf_object__open`` consists of the name of corresponding
|
||||||
|
object, ``bpf_object``, double underscore and ``open`` that defines the
|
||||||
|
purpose of the function to open ELF file and create ``bpf_object`` from
|
||||||
|
it.
|
||||||
|
|
||||||
|
Another example: ``bpf_program__load`` is named for corresponding
|
||||||
|
object, ``bpf_program``, that is separated from other part of the name
|
||||||
|
by double underscore.
|
||||||
|
|
||||||
|
All objects and corresponding functions other than BTF related should go
|
||||||
|
to ``libbpf.h``. BTF types and functions should go to ``btf.h``.
|
||||||
|
|
||||||
|
Auxiliary functions
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Auxiliary functions and types that don't fit well in any of categories
|
||||||
|
described above should have ``libbpf_`` prefix, e.g.
|
||||||
|
``libbpf_get_error`` or ``libbpf_prog_type_by_name``.
|
||||||
|
|
||||||
|
libbpf ABI
|
||||||
|
==========
|
||||||
|
|
||||||
|
libbpf can be both linked statically or used as DSO. To avoid possible
|
||||||
|
conflicts with other libraries an application is linked with, all
|
||||||
|
non-static libbpf symbols should have one of the prefixes mentioned in
|
||||||
|
API documentation above. See API naming convention to choose the right
|
||||||
|
name for a new symbol.
|
||||||
|
|
||||||
|
Symbol visibility
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
libbpf follow the model when all global symbols have visibility "hidden"
|
||||||
|
by default and to make a symbol visible it has to be explicitly
|
||||||
|
attributed with ``LIBBPF_API`` macro. For example:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
|
||||||
|
|
||||||
|
This prevents from accidentally exporting a symbol, that is not supposed
|
||||||
|
to be a part of ABI what, in turn, improves both libbpf developer- and
|
||||||
|
user-experiences.
|
||||||
|
|
||||||
|
ABI versionning
|
||||||
|
---------------
|
||||||
|
|
||||||
|
To make future ABI extensions possible libbpf ABI is versioned.
|
||||||
|
Versioning is implemented by ``libbpf.map`` version script that is
|
||||||
|
passed to linker.
|
||||||
|
|
||||||
|
Version name is ``LIBBPF_`` prefix + three-component numeric version,
|
||||||
|
starting from ``0.0.1``.
|
||||||
|
|
||||||
|
Every time ABI is being changed, e.g. because a new symbol is added or
|
||||||
|
semantic of existing symbol is changed, ABI version should be bumped.
|
||||||
|
|
||||||
|
For example, if current state of ``libbpf.map`` is:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
LIBBPF_0.0.1 {
|
||||||
|
global:
|
||||||
|
bpf_func_a;
|
||||||
|
bpf_func_b;
|
||||||
|
local:
|
||||||
|
\*;
|
||||||
|
};
|
||||||
|
|
||||||
|
, and a new symbol ``bpf_func_c`` is being introduced, then
|
||||||
|
``libbpf.map`` should be changed like this:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
LIBBPF_0.0.1 {
|
||||||
|
global:
|
||||||
|
bpf_func_a;
|
||||||
|
bpf_func_b;
|
||||||
|
local:
|
||||||
|
\*;
|
||||||
|
};
|
||||||
|
LIBBPF_0.0.2 {
|
||||||
|
global:
|
||||||
|
bpf_func_c;
|
||||||
|
} LIBBPF_0.0.1;
|
||||||
|
|
||||||
|
, where new version ``LIBBPF_0.0.2`` depends on the previous
|
||||||
|
``LIBBPF_0.0.1``.
|
||||||
|
|
||||||
|
Format of version script and ways to handle ABI changes, including
|
||||||
|
incompatible ones, described in details in [1].
|
||||||
|
|
||||||
|
Links
|
||||||
|
=====
|
||||||
|
|
||||||
|
[1] https://www.akkadia.org/drepper/dsohowto.pdf
|
||||||
|
(Chapter 3. Maintaining APIs and ABIs).
|
||||||
120
src/bpf.c
120
src/bpf.c
@@ -173,11 +173,36 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
|
|||||||
-1);
|
-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
alloc_zero_tailing_info(const void *orecord, __u32 cnt,
|
||||||
|
__u32 actual_rec_size, __u32 expected_rec_size)
|
||||||
|
{
|
||||||
|
__u64 info_len = actual_rec_size * cnt;
|
||||||
|
void *info, *nrecord;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
info = malloc(info_len);
|
||||||
|
if (!info)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* zero out bytes kernel does not understand */
|
||||||
|
nrecord = info;
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
memcpy(nrecord, orecord, expected_rec_size);
|
||||||
|
memset(nrecord + expected_rec_size, 0,
|
||||||
|
actual_rec_size - expected_rec_size);
|
||||||
|
orecord += actual_rec_size;
|
||||||
|
nrecord += actual_rec_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||||
char *log_buf, size_t log_buf_sz)
|
char *log_buf, size_t log_buf_sz)
|
||||||
{
|
{
|
||||||
|
void *finfo = NULL, *linfo = NULL;
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
void *finfo = NULL;
|
|
||||||
__u32 name_len;
|
__u32 name_len;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@@ -201,53 +226,58 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
|||||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||||
attr.func_info_cnt = load_attr->func_info_cnt;
|
attr.func_info_cnt = load_attr->func_info_cnt;
|
||||||
attr.func_info = ptr_to_u64(load_attr->func_info);
|
attr.func_info = ptr_to_u64(load_attr->func_info);
|
||||||
|
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||||
|
attr.line_info_cnt = load_attr->line_info_cnt;
|
||||||
|
attr.line_info = ptr_to_u64(load_attr->line_info);
|
||||||
memcpy(attr.prog_name, load_attr->name,
|
memcpy(attr.prog_name, load_attr->name,
|
||||||
min(name_len, BPF_OBJ_NAME_LEN - 1));
|
min(name_len, BPF_OBJ_NAME_LEN - 1));
|
||||||
|
|
||||||
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||||
if (fd >= 0 || !log_buf || !log_buf_sz)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
/* After bpf_prog_load, the kernel may modify certain attributes
|
/* After bpf_prog_load, the kernel may modify certain attributes
|
||||||
* to give user space a hint how to deal with loading failure.
|
* to give user space a hint how to deal with loading failure.
|
||||||
* Check to see whether we can make some changes and load again.
|
* Check to see whether we can make some changes and load again.
|
||||||
*/
|
*/
|
||||||
if (errno == E2BIG && attr.func_info_cnt &&
|
while (errno == E2BIG && (!finfo || !linfo)) {
|
||||||
attr.func_info_rec_size < load_attr->func_info_rec_size) {
|
if (!finfo && attr.func_info_cnt &&
|
||||||
__u32 actual_rec_size = load_attr->func_info_rec_size;
|
attr.func_info_rec_size < load_attr->func_info_rec_size) {
|
||||||
__u32 expected_rec_size = attr.func_info_rec_size;
|
/* try with corrected func info records */
|
||||||
__u32 finfo_cnt = load_attr->func_info_cnt;
|
finfo = alloc_zero_tailing_info(load_attr->func_info,
|
||||||
__u64 finfo_len = actual_rec_size * finfo_cnt;
|
load_attr->func_info_cnt,
|
||||||
const void *orecord;
|
load_attr->func_info_rec_size,
|
||||||
void *nrecord;
|
attr.func_info_rec_size);
|
||||||
int i;
|
if (!finfo)
|
||||||
|
goto done;
|
||||||
|
|
||||||
finfo = malloc(finfo_len);
|
attr.func_info = ptr_to_u64(finfo);
|
||||||
if (!finfo)
|
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
||||||
/* further try with log buffer won't help */
|
} else if (!linfo && attr.line_info_cnt &&
|
||||||
return fd;
|
attr.line_info_rec_size <
|
||||||
|
load_attr->line_info_rec_size) {
|
||||||
|
linfo = alloc_zero_tailing_info(load_attr->line_info,
|
||||||
|
load_attr->line_info_cnt,
|
||||||
|
load_attr->line_info_rec_size,
|
||||||
|
attr.line_info_rec_size);
|
||||||
|
if (!linfo)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* zero out bytes kernel does not understand */
|
attr.line_info = ptr_to_u64(linfo);
|
||||||
orecord = load_attr->func_info;
|
attr.line_info_rec_size = load_attr->line_info_rec_size;
|
||||||
nrecord = finfo;
|
} else {
|
||||||
for (i = 0; i < load_attr->func_info_cnt; i++) {
|
break;
|
||||||
memcpy(nrecord, orecord, expected_rec_size);
|
|
||||||
memset(nrecord + expected_rec_size, 0,
|
|
||||||
actual_rec_size - expected_rec_size);
|
|
||||||
orecord += actual_rec_size;
|
|
||||||
nrecord += actual_rec_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try with corrected func info records */
|
|
||||||
attr.func_info = ptr_to_u64(finfo);
|
|
||||||
attr.func_info_rec_size = load_attr->func_info_rec_size;
|
|
||||||
|
|
||||||
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||||
|
|
||||||
if (fd >= 0 || !log_buf || !log_buf_sz)
|
if (fd >= 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!log_buf || !log_buf_sz)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* Try again with log */
|
/* Try again with log */
|
||||||
attr.log_buf = ptr_to_u64(log_buf);
|
attr.log_buf = ptr_to_u64(log_buf);
|
||||||
attr.log_size = log_buf_sz;
|
attr.log_size = log_buf_sz;
|
||||||
@@ -256,6 +286,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
|||||||
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||||
done:
|
done:
|
||||||
free(finfo);
|
free(finfo);
|
||||||
|
free(linfo);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,9 +310,9 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
||||||
size_t insns_cnt, int strict_alignment,
|
size_t insns_cnt, __u32 prog_flags, const char *license,
|
||||||
const char *license, __u32 kern_version,
|
__u32 kern_version, char *log_buf, size_t log_buf_sz,
|
||||||
char *log_buf, size_t log_buf_sz, int log_level)
|
int log_level)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
|
||||||
@@ -295,7 +326,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
|
|||||||
attr.log_level = log_level;
|
attr.log_level = log_level;
|
||||||
log_buf[0] = 0;
|
log_buf[0] = 0;
|
||||||
attr.kern_version = kern_version;
|
attr.kern_version = kern_version;
|
||||||
attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0;
|
attr.prog_flags = prog_flags;
|
||||||
|
|
||||||
return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
|
||||||
}
|
}
|
||||||
@@ -463,6 +494,29 @@ int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr)
|
||||||
|
{
|
||||||
|
union bpf_attr attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!test_attr->data_out && test_attr->data_size_out > 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
bzero(&attr, sizeof(attr));
|
||||||
|
attr.test.prog_fd = test_attr->prog_fd;
|
||||||
|
attr.test.data_in = ptr_to_u64(test_attr->data_in);
|
||||||
|
attr.test.data_out = ptr_to_u64(test_attr->data_out);
|
||||||
|
attr.test.data_size_in = test_attr->data_size_in;
|
||||||
|
attr.test.data_size_out = test_attr->data_size_out;
|
||||||
|
attr.test.repeat = test_attr->repeat;
|
||||||
|
|
||||||
|
ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
|
||||||
|
test_attr->data_size_out = attr.test.data_size_out;
|
||||||
|
test_attr->retval = attr.test.retval;
|
||||||
|
test_attr->duration = attr.test.duration;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
|
|||||||
24
src/bpf.h
24
src/bpf.h
@@ -82,6 +82,9 @@ struct bpf_load_program_attr {
|
|||||||
__u32 func_info_rec_size;
|
__u32 func_info_rec_size;
|
||||||
const void *func_info;
|
const void *func_info;
|
||||||
__u32 func_info_cnt;
|
__u32 func_info_cnt;
|
||||||
|
__u32 line_info_rec_size;
|
||||||
|
const void *line_info;
|
||||||
|
__u32 line_info_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags to direct loading requirements */
|
/* Flags to direct loading requirements */
|
||||||
@@ -98,7 +101,7 @@ LIBBPF_API int bpf_load_program(enum bpf_prog_type type,
|
|||||||
char *log_buf, size_t log_buf_sz);
|
char *log_buf, size_t log_buf_sz);
|
||||||
LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
|
LIBBPF_API int bpf_verify_program(enum bpf_prog_type type,
|
||||||
const struct bpf_insn *insns,
|
const struct bpf_insn *insns,
|
||||||
size_t insns_cnt, int strict_alignment,
|
size_t insns_cnt, __u32 prog_flags,
|
||||||
const char *license, __u32 kern_version,
|
const char *license, __u32 kern_version,
|
||||||
char *log_buf, size_t log_buf_sz,
|
char *log_buf, size_t log_buf_sz,
|
||||||
int log_level);
|
int log_level);
|
||||||
@@ -118,6 +121,25 @@ LIBBPF_API int bpf_prog_attach(int prog_fd, int attachable_fd,
|
|||||||
LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
LIBBPF_API int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
|
||||||
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
LIBBPF_API int bpf_prog_detach2(int prog_fd, int attachable_fd,
|
||||||
enum bpf_attach_type type);
|
enum bpf_attach_type type);
|
||||||
|
|
||||||
|
struct bpf_prog_test_run_attr {
|
||||||
|
int prog_fd;
|
||||||
|
int repeat;
|
||||||
|
const void *data_in;
|
||||||
|
__u32 data_size_in;
|
||||||
|
void *data_out; /* optional */
|
||||||
|
__u32 data_size_out; /* in: max length of data_out
|
||||||
|
* out: length of data_out */
|
||||||
|
__u32 retval; /* out: return code of the BPF program */
|
||||||
|
__u32 duration; /* out: average per repetition in ns */
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBBPF_API int bpf_prog_test_run_xattr(struct bpf_prog_test_run_attr *test_attr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bpf_prog_test_run does not check that data_out is large enough. Consider
|
||||||
|
* using bpf_prog_test_run_xattr instead.
|
||||||
|
*/
|
||||||
LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,
|
LIBBPF_API int bpf_prog_test_run(int prog_fd, int repeat, void *data,
|
||||||
__u32 size, void *data_out, __u32 *size_out,
|
__u32 size, void *data_out, __u32 *size_out,
|
||||||
__u32 *retval, __u32 *duration);
|
__u32 *retval, __u32 *duration);
|
||||||
|
|||||||
249
src/bpf_prog_linfo.c
Normal file
249
src/bpf_prog_linfo.c
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
||||||
|
/* Copyright (c) 2018 Facebook */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include "libbpf.h"
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct bpf_prog_linfo {
|
||||||
|
void *raw_linfo;
|
||||||
|
void *raw_jited_linfo;
|
||||||
|
__u32 *nr_jited_linfo_per_func;
|
||||||
|
__u32 *jited_linfo_func_idx;
|
||||||
|
__u32 nr_linfo;
|
||||||
|
__u32 nr_jited_func;
|
||||||
|
__u32 rec_size;
|
||||||
|
__u32 jited_rec_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo,
|
||||||
|
const __u64 *ksym_func, const __u32 *ksym_len)
|
||||||
|
{
|
||||||
|
__u32 nr_jited_func, nr_linfo;
|
||||||
|
const void *raw_jited_linfo;
|
||||||
|
const __u64 *jited_linfo;
|
||||||
|
__u64 last_jited_linfo;
|
||||||
|
/*
|
||||||
|
* Index to raw_jited_linfo:
|
||||||
|
* i: Index for searching the next ksym_func
|
||||||
|
* prev_i: Index to the last found ksym_func
|
||||||
|
*/
|
||||||
|
__u32 i, prev_i;
|
||||||
|
__u32 f; /* Index to ksym_func */
|
||||||
|
|
||||||
|
raw_jited_linfo = prog_linfo->raw_jited_linfo;
|
||||||
|
jited_linfo = raw_jited_linfo;
|
||||||
|
if (ksym_func[0] != *jited_linfo)
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
prog_linfo->jited_linfo_func_idx[0] = 0;
|
||||||
|
nr_jited_func = prog_linfo->nr_jited_func;
|
||||||
|
nr_linfo = prog_linfo->nr_linfo;
|
||||||
|
|
||||||
|
for (prev_i = 0, i = 1, f = 1;
|
||||||
|
i < nr_linfo && f < nr_jited_func;
|
||||||
|
i++) {
|
||||||
|
raw_jited_linfo += prog_linfo->jited_rec_size;
|
||||||
|
last_jited_linfo = *jited_linfo;
|
||||||
|
jited_linfo = raw_jited_linfo;
|
||||||
|
|
||||||
|
if (ksym_func[f] == *jited_linfo) {
|
||||||
|
prog_linfo->jited_linfo_func_idx[f] = i;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (last_jited_linfo - ksym_func[f - 1] + 1 >
|
||||||
|
ksym_len[f - 1])
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
prog_linfo->nr_jited_linfo_per_func[f - 1] =
|
||||||
|
i - prev_i;
|
||||||
|
prev_i = i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ksym_func[f] is found in jited_linfo.
|
||||||
|
* Look for the next one.
|
||||||
|
*/
|
||||||
|
f++;
|
||||||
|
} else if (*jited_linfo <= last_jited_linfo) {
|
||||||
|
/* Ensure the addr is increasing _within_ a func */
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f != nr_jited_func)
|
||||||
|
goto errout;
|
||||||
|
|
||||||
|
prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] =
|
||||||
|
nr_linfo - prev_i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo)
|
||||||
|
{
|
||||||
|
if (!prog_linfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(prog_linfo->raw_linfo);
|
||||||
|
free(prog_linfo->raw_jited_linfo);
|
||||||
|
free(prog_linfo->nr_jited_linfo_per_func);
|
||||||
|
free(prog_linfo->jited_linfo_func_idx);
|
||||||
|
free(prog_linfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
|
||||||
|
{
|
||||||
|
struct bpf_prog_linfo *prog_linfo;
|
||||||
|
__u32 nr_linfo, nr_jited_func;
|
||||||
|
|
||||||
|
nr_linfo = info->nr_line_info;
|
||||||
|
|
||||||
|
if (!nr_linfo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The min size that bpf_prog_linfo has to access for
|
||||||
|
* searching purpose.
|
||||||
|
*/
|
||||||
|
if (info->line_info_rec_size <
|
||||||
|
offsetof(struct bpf_line_info, file_name_off))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
prog_linfo = calloc(1, sizeof(*prog_linfo));
|
||||||
|
if (!prog_linfo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Copy xlated line_info */
|
||||||
|
prog_linfo->nr_linfo = nr_linfo;
|
||||||
|
prog_linfo->rec_size = info->line_info_rec_size;
|
||||||
|
prog_linfo->raw_linfo = malloc(nr_linfo * prog_linfo->rec_size);
|
||||||
|
if (!prog_linfo->raw_linfo)
|
||||||
|
goto err_free;
|
||||||
|
memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info,
|
||||||
|
nr_linfo * prog_linfo->rec_size);
|
||||||
|
|
||||||
|
nr_jited_func = info->nr_jited_ksyms;
|
||||||
|
if (!nr_jited_func ||
|
||||||
|
!info->jited_line_info ||
|
||||||
|
info->nr_jited_line_info != nr_linfo ||
|
||||||
|
info->jited_line_info_rec_size < sizeof(__u64) ||
|
||||||
|
info->nr_jited_func_lens != nr_jited_func ||
|
||||||
|
!info->jited_ksyms ||
|
||||||
|
!info->jited_func_lens)
|
||||||
|
/* Not enough info to provide jited_line_info */
|
||||||
|
return prog_linfo;
|
||||||
|
|
||||||
|
/* Copy jited_line_info */
|
||||||
|
prog_linfo->nr_jited_func = nr_jited_func;
|
||||||
|
prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
|
||||||
|
prog_linfo->raw_jited_linfo = malloc(nr_linfo *
|
||||||
|
prog_linfo->jited_rec_size);
|
||||||
|
if (!prog_linfo->raw_jited_linfo)
|
||||||
|
goto err_free;
|
||||||
|
memcpy(prog_linfo->raw_jited_linfo,
|
||||||
|
(void *)(long)info->jited_line_info,
|
||||||
|
nr_linfo * prog_linfo->jited_rec_size);
|
||||||
|
|
||||||
|
/* Number of jited_line_info per jited func */
|
||||||
|
prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
|
||||||
|
sizeof(__u32));
|
||||||
|
if (!prog_linfo->nr_jited_linfo_per_func)
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each jited func,
|
||||||
|
* the start idx to the "linfo" and "jited_linfo" array,
|
||||||
|
*/
|
||||||
|
prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func *
|
||||||
|
sizeof(__u32));
|
||||||
|
if (!prog_linfo->jited_linfo_func_idx)
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
|
if (dissect_jited_func(prog_linfo,
|
||||||
|
(__u64 *)(long)info->jited_ksyms,
|
||||||
|
(__u32 *)(long)info->jited_func_lens))
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
|
return prog_linfo;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
bpf_prog_linfo__free(prog_linfo);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct bpf_line_info *
|
||||||
|
bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
|
||||||
|
__u64 addr, __u32 func_idx, __u32 nr_skip)
|
||||||
|
{
|
||||||
|
__u32 jited_rec_size, rec_size, nr_linfo, start, i;
|
||||||
|
const void *raw_jited_linfo, *raw_linfo;
|
||||||
|
const __u64 *jited_linfo;
|
||||||
|
|
||||||
|
if (func_idx >= prog_linfo->nr_jited_func)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
|
||||||
|
if (nr_skip >= nr_linfo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
|
||||||
|
jited_rec_size = prog_linfo->jited_rec_size;
|
||||||
|
raw_jited_linfo = prog_linfo->raw_jited_linfo +
|
||||||
|
(start * jited_rec_size);
|
||||||
|
jited_linfo = raw_jited_linfo;
|
||||||
|
if (addr < *jited_linfo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nr_linfo -= nr_skip;
|
||||||
|
rec_size = prog_linfo->rec_size;
|
||||||
|
raw_linfo = prog_linfo->raw_linfo + (start * rec_size);
|
||||||
|
for (i = 0; i < nr_linfo; i++) {
|
||||||
|
if (addr < *jited_linfo)
|
||||||
|
break;
|
||||||
|
|
||||||
|
raw_linfo += rec_size;
|
||||||
|
raw_jited_linfo += jited_rec_size;
|
||||||
|
jited_linfo = raw_jited_linfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return raw_linfo - rec_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct bpf_line_info *
|
||||||
|
bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
|
||||||
|
__u32 insn_off, __u32 nr_skip)
|
||||||
|
{
|
||||||
|
const struct bpf_line_info *linfo;
|
||||||
|
__u32 rec_size, nr_linfo, i;
|
||||||
|
const void *raw_linfo;
|
||||||
|
|
||||||
|
nr_linfo = prog_linfo->nr_linfo;
|
||||||
|
if (nr_skip >= nr_linfo)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
rec_size = prog_linfo->rec_size;
|
||||||
|
raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
|
||||||
|
linfo = raw_linfo;
|
||||||
|
if (insn_off < linfo->insn_off)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nr_linfo -= nr_skip;
|
||||||
|
for (i = 0; i < nr_linfo; i++) {
|
||||||
|
if (insn_off < linfo->insn_off)
|
||||||
|
break;
|
||||||
|
|
||||||
|
raw_linfo += rec_size;
|
||||||
|
linfo = raw_linfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return raw_linfo - rec_size;
|
||||||
|
}
|
||||||
352
src/btf.c
352
src/btf.c
@@ -37,18 +37,43 @@ struct btf {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct btf_ext_info {
|
||||||
|
/*
|
||||||
|
* info points to a deep copy of the individual info section
|
||||||
|
* (e.g. func_info and line_info) from the .BTF.ext.
|
||||||
|
* It does not include the __u32 rec_size.
|
||||||
|
*/
|
||||||
|
void *info;
|
||||||
|
__u32 rec_size;
|
||||||
|
__u32 len;
|
||||||
|
};
|
||||||
|
|
||||||
struct btf_ext {
|
struct btf_ext {
|
||||||
void *func_info;
|
struct btf_ext_info func_info;
|
||||||
__u32 func_info_rec_size;
|
struct btf_ext_info line_info;
|
||||||
__u32 func_info_len;
|
};
|
||||||
|
|
||||||
|
struct btf_ext_info_sec {
|
||||||
|
__u32 sec_name_off;
|
||||||
|
__u32 num_info;
|
||||||
|
/* Followed by num_info * record_size number of bytes */
|
||||||
|
__u8 data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The minimum bpf_func_info checked by the loader */
|
/* The minimum bpf_func_info checked by the loader */
|
||||||
struct bpf_func_info_min {
|
struct bpf_func_info_min {
|
||||||
__u32 insn_offset;
|
__u32 insn_off;
|
||||||
__u32 type_id;
|
__u32 type_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The minimum bpf_line_info checked by the loader */
|
||||||
|
struct bpf_line_info_min {
|
||||||
|
__u32 insn_off;
|
||||||
|
__u32 file_name_off;
|
||||||
|
__u32 line_off;
|
||||||
|
__u32 line_col;
|
||||||
|
};
|
||||||
|
|
||||||
static inline __u64 ptr_to_u64(const void *ptr)
|
static inline __u64 ptr_to_u64(const void *ptr)
|
||||||
{
|
{
|
||||||
return (__u64) (unsigned long) ptr;
|
return (__u64) (unsigned long) ptr;
|
||||||
@@ -415,7 +440,7 @@ const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btf_get_from_id(__u32 id, struct btf **btf)
|
int btf__get_from_id(__u32 id, struct btf **btf)
|
||||||
{
|
{
|
||||||
struct bpf_btf_info btf_info = { 0 };
|
struct bpf_btf_info btf_info = { 0 };
|
||||||
__u32 len = sizeof(btf_info);
|
__u32 len = sizeof(btf_info);
|
||||||
@@ -466,7 +491,7 @@ int btf_get_from_id(__u32 id, struct btf **btf)
|
|||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
*btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL);
|
*btf = btf__new((__u8 *)(long)btf_info.btf, btf_info.btf_size, NULL);
|
||||||
if (IS_ERR(*btf)) {
|
if (IS_ERR(*btf)) {
|
||||||
err = PTR_ERR(*btf);
|
err = PTR_ERR(*btf);
|
||||||
*btf = NULL;
|
*btf = NULL;
|
||||||
@@ -479,71 +504,147 @@ exit_free:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btf_ext_validate_func_info(const void *finfo, __u32 size,
|
struct btf_ext_sec_copy_param {
|
||||||
btf_print_fn_t err_log)
|
__u32 off;
|
||||||
|
__u32 len;
|
||||||
|
__u32 min_rec_size;
|
||||||
|
struct btf_ext_info *ext_info;
|
||||||
|
const char *desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int btf_ext_copy_info(struct btf_ext *btf_ext,
|
||||||
|
__u8 *data, __u32 data_size,
|
||||||
|
struct btf_ext_sec_copy_param *ext_sec,
|
||||||
|
btf_print_fn_t err_log)
|
||||||
{
|
{
|
||||||
int sec_hdrlen = sizeof(struct btf_sec_func_info);
|
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||||
__u32 size_left, num_records, record_size;
|
const struct btf_ext_info_sec *sinfo;
|
||||||
const struct btf_sec_func_info *sinfo;
|
struct btf_ext_info *ext_info;
|
||||||
__u64 total_record_size;
|
__u32 info_left, record_size;
|
||||||
|
/* The start of the info sec (including the __u32 record_size). */
|
||||||
|
const void *info;
|
||||||
|
|
||||||
/* At least a func_info record size */
|
/* data and data_size do not include btf_ext_header from now on */
|
||||||
if (size < sizeof(__u32)) {
|
data = data + hdr->hdr_len;
|
||||||
elog("BTF.ext func_info record size not found");
|
data_size -= hdr->hdr_len;
|
||||||
|
|
||||||
|
if (ext_sec->off & 0x03) {
|
||||||
|
elog(".BTF.ext %s section is not aligned to 4 bytes\n",
|
||||||
|
ext_sec->desc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The record size needs to meet below minimum standard */
|
if (data_size < ext_sec->off ||
|
||||||
record_size = *(__u32 *)finfo;
|
ext_sec->len > data_size - ext_sec->off) {
|
||||||
if (record_size < sizeof(struct bpf_func_info_min) ||
|
elog("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
|
||||||
record_size % sizeof(__u32)) {
|
ext_sec->desc, ext_sec->off, ext_sec->len);
|
||||||
elog("BTF.ext func_info invalid record size");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sinfo = finfo + sizeof(__u32);
|
info = data + ext_sec->off;
|
||||||
size_left = size - sizeof(__u32);
|
info_left = ext_sec->len;
|
||||||
|
|
||||||
/* If no func_info records, return failure now so .BTF.ext
|
/* At least a record size */
|
||||||
* won't be used.
|
if (info_left < sizeof(__u32)) {
|
||||||
*/
|
elog(".BTF.ext %s record size not found\n", ext_sec->desc);
|
||||||
if (!size_left) {
|
|
||||||
elog("BTF.ext no func info records");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (size_left) {
|
/* The record size needs to meet the minimum standard */
|
||||||
if (size_left < sec_hdrlen) {
|
record_size = *(__u32 *)info;
|
||||||
elog("BTF.ext func_info header not found");
|
if (record_size < ext_sec->min_rec_size ||
|
||||||
|
record_size & 0x03) {
|
||||||
|
elog("%s section in .BTF.ext has invalid record size %u\n",
|
||||||
|
ext_sec->desc, record_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo = info + sizeof(__u32);
|
||||||
|
info_left -= sizeof(__u32);
|
||||||
|
|
||||||
|
/* If no records, return failure now so .BTF.ext won't be used. */
|
||||||
|
if (!info_left) {
|
||||||
|
elog("%s section in .BTF.ext has no records", ext_sec->desc);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (info_left) {
|
||||||
|
unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
|
||||||
|
__u64 total_record_size;
|
||||||
|
__u32 num_records;
|
||||||
|
|
||||||
|
if (info_left < sec_hdrlen) {
|
||||||
|
elog("%s section header is not found in .BTF.ext\n",
|
||||||
|
ext_sec->desc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_records = sinfo->num_func_info;
|
num_records = sinfo->num_info;
|
||||||
if (num_records == 0) {
|
if (num_records == 0) {
|
||||||
elog("incorrect BTF.ext num_func_info");
|
elog("%s section has incorrect num_records in .BTF.ext\n",
|
||||||
|
ext_sec->desc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_record_size = sec_hdrlen +
|
total_record_size = sec_hdrlen +
|
||||||
(__u64)num_records * record_size;
|
(__u64)num_records * record_size;
|
||||||
if (size_left < total_record_size) {
|
if (info_left < total_record_size) {
|
||||||
elog("incorrect BTF.ext num_func_info");
|
elog("%s section has incorrect num_records in .BTF.ext\n",
|
||||||
|
ext_sec->desc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_left -= total_record_size;
|
info_left -= total_record_size;
|
||||||
sinfo = (void *)sinfo + total_record_size;
|
sinfo = (void *)sinfo + total_record_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ext_info = ext_sec->ext_info;
|
||||||
|
ext_info->len = ext_sec->len - sizeof(__u32);
|
||||||
|
ext_info->rec_size = record_size;
|
||||||
|
ext_info->info = malloc(ext_info->len);
|
||||||
|
if (!ext_info->info)
|
||||||
|
return -ENOMEM;
|
||||||
|
memcpy(ext_info->info, info + sizeof(__u32), ext_info->len);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btf_ext_copy_func_info(struct btf_ext *btf_ext,
|
||||||
|
__u8 *data, __u32 data_size,
|
||||||
|
btf_print_fn_t err_log)
|
||||||
|
{
|
||||||
|
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||||
|
struct btf_ext_sec_copy_param param = {
|
||||||
|
.off = hdr->func_info_off,
|
||||||
|
.len = hdr->func_info_len,
|
||||||
|
.min_rec_size = sizeof(struct bpf_func_info_min),
|
||||||
|
.ext_info = &btf_ext->func_info,
|
||||||
|
.desc = "func_info"
|
||||||
|
};
|
||||||
|
|
||||||
|
return btf_ext_copy_info(btf_ext, data, data_size, ¶m, err_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btf_ext_copy_line_info(struct btf_ext *btf_ext,
|
||||||
|
__u8 *data, __u32 data_size,
|
||||||
|
btf_print_fn_t err_log)
|
||||||
|
{
|
||||||
|
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||||
|
struct btf_ext_sec_copy_param param = {
|
||||||
|
.off = hdr->line_info_off,
|
||||||
|
.len = hdr->line_info_len,
|
||||||
|
.min_rec_size = sizeof(struct bpf_line_info_min),
|
||||||
|
.ext_info = &btf_ext->line_info,
|
||||||
|
.desc = "line_info",
|
||||||
|
};
|
||||||
|
|
||||||
|
return btf_ext_copy_info(btf_ext, data, data_size, ¶m, err_log);
|
||||||
|
}
|
||||||
|
|
||||||
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
|
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
|
||||||
btf_print_fn_t err_log)
|
btf_print_fn_t err_log)
|
||||||
{
|
{
|
||||||
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
|
||||||
__u32 meta_left, last_func_info_pos;
|
|
||||||
void *finfo;
|
|
||||||
|
|
||||||
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
|
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
|
||||||
data_size < hdr->hdr_len) {
|
data_size < hdr->hdr_len) {
|
||||||
@@ -566,34 +667,12 @@ static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
|
|||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
meta_left = data_size - hdr->hdr_len;
|
if (data_size == hdr->hdr_len) {
|
||||||
if (!meta_left) {
|
|
||||||
elog("BTF.ext has no data\n");
|
elog("BTF.ext has no data\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta_left < hdr->func_info_off) {
|
return 0;
|
||||||
elog("Invalid BTF.ext func_info section offset:%u\n",
|
|
||||||
hdr->func_info_off);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr->func_info_off & 0x03) {
|
|
||||||
elog("BTF.ext func_info section is not aligned to 4 bytes\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_func_info_pos = hdr->hdr_len + hdr->func_info_off +
|
|
||||||
hdr->func_info_len;
|
|
||||||
if (last_func_info_pos > data_size) {
|
|
||||||
elog("Invalid BTF.ext func_info section size:%u\n",
|
|
||||||
hdr->func_info_len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
finfo = data + hdr->hdr_len + hdr->func_info_off;
|
|
||||||
return btf_ext_validate_func_info(finfo, hdr->func_info_len,
|
|
||||||
err_log);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void btf_ext__free(struct btf_ext *btf_ext)
|
void btf_ext__free(struct btf_ext *btf_ext)
|
||||||
@@ -601,16 +680,14 @@ void btf_ext__free(struct btf_ext *btf_ext)
|
|||||||
if (!btf_ext)
|
if (!btf_ext)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
free(btf_ext->func_info);
|
free(btf_ext->func_info.info);
|
||||||
|
free(btf_ext->line_info.info);
|
||||||
free(btf_ext);
|
free(btf_ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
|
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
|
||||||
{
|
{
|
||||||
const struct btf_ext_header *hdr;
|
|
||||||
struct btf_ext *btf_ext;
|
struct btf_ext *btf_ext;
|
||||||
void *org_fdata, *fdata;
|
|
||||||
__u32 hdrlen, size_u32;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = btf_ext_parse_hdr(data, size, err_log);
|
err = btf_ext_parse_hdr(data, size, err_log);
|
||||||
@@ -621,94 +698,38 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
|
|||||||
if (!btf_ext)
|
if (!btf_ext)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
hdr = (const struct btf_ext_header *)data;
|
err = btf_ext_copy_func_info(btf_ext, data, size, err_log);
|
||||||
hdrlen = hdr->hdr_len;
|
if (err) {
|
||||||
size_u32 = sizeof(__u32);
|
btf_ext__free(btf_ext);
|
||||||
fdata = malloc(hdr->func_info_len - size_u32);
|
return ERR_PTR(err);
|
||||||
if (!fdata) {
|
|
||||||
free(btf_ext);
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remember record size and copy rest of func_info data */
|
err = btf_ext_copy_line_info(btf_ext, data, size, err_log);
|
||||||
org_fdata = data + hdrlen + hdr->func_info_off;
|
if (err) {
|
||||||
btf_ext->func_info_rec_size = *(__u32 *)org_fdata;
|
btf_ext__free(btf_ext);
|
||||||
memcpy(fdata, org_fdata + size_u32, hdr->func_info_len - size_u32);
|
return ERR_PTR(err);
|
||||||
btf_ext->func_info = fdata;
|
}
|
||||||
btf_ext->func_info_len = hdr->func_info_len - size_u32;
|
|
||||||
|
|
||||||
return btf_ext;
|
return btf_ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
|
static int btf_ext_reloc_info(const struct btf *btf,
|
||||||
const char *sec_name, void **func_info,
|
const struct btf_ext_info *ext_info,
|
||||||
__u32 *func_info_rec_size, __u32 *func_info_len)
|
const char *sec_name, __u32 insns_cnt,
|
||||||
|
void **info, __u32 *cnt)
|
||||||
{
|
{
|
||||||
__u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
|
__u32 sec_hdrlen = sizeof(struct btf_ext_info_sec);
|
||||||
__u32 i, record_size, records_len;
|
__u32 i, record_size, existing_len, records_len;
|
||||||
struct btf_sec_func_info *sinfo;
|
struct btf_ext_info_sec *sinfo;
|
||||||
const char *info_sec_name;
|
|
||||||
__s64 remain_len;
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
record_size = btf_ext->func_info_rec_size;
|
|
||||||
sinfo = btf_ext->func_info;
|
|
||||||
remain_len = btf_ext->func_info_len;
|
|
||||||
|
|
||||||
while (remain_len > 0) {
|
|
||||||
records_len = sinfo->num_func_info * record_size;
|
|
||||||
info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
|
|
||||||
if (strcmp(info_sec_name, sec_name)) {
|
|
||||||
remain_len -= sec_hdrlen + records_len;
|
|
||||||
sinfo = (void *)sinfo + sec_hdrlen + records_len;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = malloc(records_len);
|
|
||||||
if (!data)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
memcpy(data, sinfo->data, records_len);
|
|
||||||
|
|
||||||
/* adjust the insn_offset, the data in .BTF.ext is
|
|
||||||
* the actual byte offset, and the kernel expects
|
|
||||||
* the offset in term of bpf_insn.
|
|
||||||
*
|
|
||||||
* adjust the insn offset only, the rest data will
|
|
||||||
* be passed to kernel.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < sinfo->num_func_info; i++) {
|
|
||||||
struct bpf_func_info_min *record;
|
|
||||||
|
|
||||||
record = data + i * record_size;
|
|
||||||
record->insn_offset /= sizeof(struct bpf_insn);
|
|
||||||
}
|
|
||||||
|
|
||||||
*func_info = data;
|
|
||||||
*func_info_len = records_len;
|
|
||||||
*func_info_rec_size = record_size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
|
|
||||||
const char *sec_name, __u32 insns_cnt,
|
|
||||||
void **func_info, __u32 *func_info_len)
|
|
||||||
{
|
|
||||||
__u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
|
|
||||||
__u32 i, record_size, existing_flen, records_len;
|
|
||||||
struct btf_sec_func_info *sinfo;
|
|
||||||
const char *info_sec_name;
|
const char *info_sec_name;
|
||||||
__u64 remain_len;
|
__u64 remain_len;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
record_size = btf_ext->func_info_rec_size;
|
record_size = ext_info->rec_size;
|
||||||
sinfo = btf_ext->func_info;
|
sinfo = ext_info->info;
|
||||||
remain_len = btf_ext->func_info_len;
|
remain_len = ext_info->len;
|
||||||
while (remain_len > 0) {
|
while (remain_len > 0) {
|
||||||
records_len = sinfo->num_func_info * record_size;
|
records_len = sinfo->num_info * record_size;
|
||||||
info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
|
info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
|
||||||
if (strcmp(info_sec_name, sec_name)) {
|
if (strcmp(info_sec_name, sec_name)) {
|
||||||
remain_len -= sec_hdrlen + records_len;
|
remain_len -= sec_hdrlen + records_len;
|
||||||
@@ -716,27 +737,52 @@ int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
existing_flen = *func_info_len;
|
existing_len = (*cnt) * record_size;
|
||||||
data = realloc(*func_info, existing_flen + records_len);
|
data = realloc(*info, existing_len + records_len);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
memcpy(data + existing_flen, sinfo->data, records_len);
|
memcpy(data + existing_len, sinfo->data, records_len);
|
||||||
/* adjust insn_offset only, the rest data will be passed
|
/* adjust insn_off only, the rest data will be passed
|
||||||
* to the kernel.
|
* to the kernel.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < sinfo->num_func_info; i++) {
|
for (i = 0; i < sinfo->num_info; i++) {
|
||||||
struct bpf_func_info_min *record;
|
__u32 *insn_off;
|
||||||
|
|
||||||
record = data + existing_flen + i * record_size;
|
insn_off = data + existing_len + (i * record_size);
|
||||||
record->insn_offset =
|
*insn_off = *insn_off / sizeof(struct bpf_insn) +
|
||||||
record->insn_offset / sizeof(struct bpf_insn) +
|
|
||||||
insns_cnt;
|
insns_cnt;
|
||||||
}
|
}
|
||||||
*func_info = data;
|
*info = data;
|
||||||
*func_info_len = existing_flen + records_len;
|
*cnt += sinfo->num_info;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btf_ext__reloc_func_info(const struct btf *btf, const struct btf_ext *btf_ext,
|
||||||
|
const char *sec_name, __u32 insns_cnt,
|
||||||
|
void **func_info, __u32 *cnt)
|
||||||
|
{
|
||||||
|
return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name,
|
||||||
|
insns_cnt, func_info, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int btf_ext__reloc_line_info(const struct btf *btf, const struct btf_ext *btf_ext,
|
||||||
|
const char *sec_name, __u32 insns_cnt,
|
||||||
|
void **line_info, __u32 *cnt)
|
||||||
|
{
|
||||||
|
return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name,
|
||||||
|
insns_cnt, line_info, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext)
|
||||||
|
{
|
||||||
|
return btf_ext->func_info.rec_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
__u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext)
|
||||||
|
{
|
||||||
|
return btf_ext->line_info.rec_size;
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/btf.h
27
src/btf.h
@@ -51,13 +51,8 @@ struct btf_ext_header {
|
|||||||
/* All offsets are in bytes relative to the end of this header */
|
/* All offsets are in bytes relative to the end of this header */
|
||||||
__u32 func_info_off;
|
__u32 func_info_off;
|
||||||
__u32 func_info_len;
|
__u32 func_info_len;
|
||||||
};
|
__u32 line_info_off;
|
||||||
|
__u32 line_info_len;
|
||||||
struct btf_sec_func_info {
|
|
||||||
__u32 sec_name_off;
|
|
||||||
__u32 num_func_info;
|
|
||||||
/* Followed by num_func_info number of bpf func_info records */
|
|
||||||
__u8 data[0];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*btf_print_fn_t)(const char *, ...)
|
typedef int (*btf_print_fn_t)(const char *, ...)
|
||||||
@@ -73,16 +68,20 @@ LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
|
|||||||
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
|
||||||
LIBBPF_API int btf__fd(const struct btf *btf);
|
LIBBPF_API int btf__fd(const struct btf *btf);
|
||||||
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
|
||||||
LIBBPF_API int btf_get_from_id(__u32 id, struct btf **btf);
|
LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
|
||||||
|
|
||||||
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
|
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
|
||||||
void btf_ext__free(struct btf_ext *btf_ext);
|
void btf_ext__free(struct btf_ext *btf_ext);
|
||||||
int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
|
int btf_ext__reloc_func_info(const struct btf *btf,
|
||||||
const char *sec_name, void **func_info,
|
const struct btf_ext *btf_ext,
|
||||||
__u32 *func_info_rec_size, __u32 *func_info_len);
|
const char *sec_name, __u32 insns_cnt,
|
||||||
int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
|
void **func_info, __u32 *func_info_len);
|
||||||
const char *sec_name, __u32 insns_cnt, void **func_info,
|
int btf_ext__reloc_line_info(const struct btf *btf,
|
||||||
__u32 *func_info_len);
|
const struct btf_ext *btf_ext,
|
||||||
|
const char *sec_name, __u32 insns_cnt,
|
||||||
|
void **line_info, __u32 *cnt);
|
||||||
|
__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
|
||||||
|
__u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
162
src/libbpf.c
162
src/libbpf.c
@@ -9,7 +9,9 @@
|
|||||||
* Copyright (C) 2017 Nicira, Inc.
|
* Copyright (C) 2017 Nicira, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -165,9 +167,13 @@ struct bpf_program {
|
|||||||
int btf_fd;
|
int btf_fd;
|
||||||
void *func_info;
|
void *func_info;
|
||||||
__u32 func_info_rec_size;
|
__u32 func_info_rec_size;
|
||||||
__u32 func_info_len;
|
__u32 func_info_cnt;
|
||||||
|
|
||||||
struct bpf_capabilities *caps;
|
struct bpf_capabilities *caps;
|
||||||
|
|
||||||
|
void *line_info;
|
||||||
|
__u32 line_info_rec_size;
|
||||||
|
__u32 line_info_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_map {
|
struct bpf_map {
|
||||||
@@ -260,6 +266,7 @@ void bpf_program__unload(struct bpf_program *prog)
|
|||||||
|
|
||||||
zclose(prog->btf_fd);
|
zclose(prog->btf_fd);
|
||||||
zfree(&prog->func_info);
|
zfree(&prog->func_info);
|
||||||
|
zfree(&prog->line_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bpf_program__exit(struct bpf_program *prog)
|
static void bpf_program__exit(struct bpf_program *prog)
|
||||||
@@ -777,6 +784,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
|
|||||||
{
|
{
|
||||||
Elf *elf = obj->efile.elf;
|
Elf *elf = obj->efile.elf;
|
||||||
GElf_Ehdr *ep = &obj->efile.ehdr;
|
GElf_Ehdr *ep = &obj->efile.ehdr;
|
||||||
|
Elf_Data *btf_ext_data = NULL;
|
||||||
Elf_Scn *scn = NULL;
|
Elf_Scn *scn = NULL;
|
||||||
int idx = 0, err = 0;
|
int idx = 0, err = 0;
|
||||||
|
|
||||||
@@ -839,14 +847,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
|
|||||||
obj->btf = NULL;
|
obj->btf = NULL;
|
||||||
}
|
}
|
||||||
} else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
|
} else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
|
||||||
obj->btf_ext = btf_ext__new(data->d_buf, data->d_size,
|
btf_ext_data = data;
|
||||||
__pr_debug);
|
|
||||||
if (IS_ERR(obj->btf_ext)) {
|
|
||||||
pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
|
|
||||||
BTF_EXT_ELF_SEC,
|
|
||||||
PTR_ERR(obj->btf_ext));
|
|
||||||
obj->btf_ext = NULL;
|
|
||||||
}
|
|
||||||
} else if (sh.sh_type == SHT_SYMTAB) {
|
} else if (sh.sh_type == SHT_SYMTAB) {
|
||||||
if (obj->efile.symbols) {
|
if (obj->efile.symbols) {
|
||||||
pr_warning("bpf: multiple SYMTAB in %s\n",
|
pr_warning("bpf: multiple SYMTAB in %s\n",
|
||||||
@@ -908,6 +909,22 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
|
|||||||
pr_warning("Corrupted ELF file: index of strtab invalid\n");
|
pr_warning("Corrupted ELF file: index of strtab invalid\n");
|
||||||
return LIBBPF_ERRNO__FORMAT;
|
return LIBBPF_ERRNO__FORMAT;
|
||||||
}
|
}
|
||||||
|
if (btf_ext_data) {
|
||||||
|
if (!obj->btf) {
|
||||||
|
pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n",
|
||||||
|
BTF_EXT_ELF_SEC, BTF_ELF_SEC);
|
||||||
|
} else {
|
||||||
|
obj->btf_ext = btf_ext__new(btf_ext_data->d_buf,
|
||||||
|
btf_ext_data->d_size,
|
||||||
|
__pr_debug);
|
||||||
|
if (IS_ERR(obj->btf_ext)) {
|
||||||
|
pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
|
||||||
|
BTF_EXT_ELF_SEC,
|
||||||
|
PTR_ERR(obj->btf_ext));
|
||||||
|
obj->btf_ext = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (obj->efile.maps_shndx >= 0) {
|
if (obj->efile.maps_shndx >= 0) {
|
||||||
err = bpf_object__init_maps(obj, flags);
|
err = bpf_object__init_maps(obj, flags);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -1273,6 +1290,82 @@ bpf_object__create_maps(struct bpf_object *obj)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_btf_ext_reloc_err(struct bpf_program *prog, int err,
|
||||||
|
void *btf_prog_info, const char *info_name)
|
||||||
|
{
|
||||||
|
if (err != -ENOENT) {
|
||||||
|
pr_warning("Error in loading %s for sec %s.\n",
|
||||||
|
info_name, prog->section_name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* err == -ENOENT (i.e. prog->section_name not found in btf_ext) */
|
||||||
|
|
||||||
|
if (btf_prog_info) {
|
||||||
|
/*
|
||||||
|
* Some info has already been found but has problem
|
||||||
|
* in the last btf_ext reloc. Must have to error
|
||||||
|
* out.
|
||||||
|
*/
|
||||||
|
pr_warning("Error in relocating %s for sec %s.\n",
|
||||||
|
info_name, prog->section_name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Have problem loading the very first info. Ignore
|
||||||
|
* the rest.
|
||||||
|
*/
|
||||||
|
pr_warning("Cannot find %s for main program sec %s. Ignore all %s.\n",
|
||||||
|
info_name, prog->section_name, info_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
|
||||||
|
const char *section_name, __u32 insn_offset)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!insn_offset || prog->func_info) {
|
||||||
|
/*
|
||||||
|
* !insn_offset => main program
|
||||||
|
*
|
||||||
|
* For sub prog, the main program's func_info has to
|
||||||
|
* be loaded first (i.e. prog->func_info != NULL)
|
||||||
|
*/
|
||||||
|
err = btf_ext__reloc_func_info(obj->btf, obj->btf_ext,
|
||||||
|
section_name, insn_offset,
|
||||||
|
&prog->func_info,
|
||||||
|
&prog->func_info_cnt);
|
||||||
|
if (err)
|
||||||
|
return check_btf_ext_reloc_err(prog, err,
|
||||||
|
prog->func_info,
|
||||||
|
"bpf_func_info");
|
||||||
|
|
||||||
|
prog->func_info_rec_size = btf_ext__func_info_rec_size(obj->btf_ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!insn_offset || prog->line_info) {
|
||||||
|
err = btf_ext__reloc_line_info(obj->btf, obj->btf_ext,
|
||||||
|
section_name, insn_offset,
|
||||||
|
&prog->line_info,
|
||||||
|
&prog->line_info_cnt);
|
||||||
|
if (err)
|
||||||
|
return check_btf_ext_reloc_err(prog, err,
|
||||||
|
prog->line_info,
|
||||||
|
"bpf_line_info");
|
||||||
|
|
||||||
|
prog->line_info_rec_size = btf_ext__line_info_rec_size(obj->btf_ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!insn_offset)
|
||||||
|
prog->btf_fd = btf__fd(obj->btf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
||||||
struct reloc_desc *relo)
|
struct reloc_desc *relo)
|
||||||
@@ -1304,17 +1397,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->btf && obj->btf_ext) {
|
if (obj->btf_ext) {
|
||||||
err = btf_ext__reloc(obj->btf, obj->btf_ext,
|
err = bpf_program_reloc_btf_ext(prog, obj,
|
||||||
text->section_name,
|
text->section_name,
|
||||||
prog->insns_cnt,
|
prog->insns_cnt);
|
||||||
&prog->func_info,
|
if (err)
|
||||||
&prog->func_info_len);
|
|
||||||
if (err) {
|
|
||||||
pr_warning("error in btf_ext__reloc for sec %s\n",
|
|
||||||
text->section_name);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(new_insn + prog->insns_cnt, text->insns,
|
memcpy(new_insn + prog->insns_cnt, text->insns,
|
||||||
@@ -1339,18 +1427,11 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
|
|||||||
if (!prog)
|
if (!prog)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (obj->btf && obj->btf_ext) {
|
if (obj->btf_ext) {
|
||||||
err = btf_ext__reloc_init(obj->btf, obj->btf_ext,
|
err = bpf_program_reloc_btf_ext(prog, obj,
|
||||||
prog->section_name,
|
prog->section_name, 0);
|
||||||
&prog->func_info,
|
if (err)
|
||||||
&prog->func_info_rec_size,
|
|
||||||
&prog->func_info_len);
|
|
||||||
if (err) {
|
|
||||||
pr_warning("err in btf_ext__reloc_init for sec %s\n",
|
|
||||||
prog->section_name);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
prog->btf_fd = btf__fd(obj->btf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prog->reloc_desc)
|
if (!prog->reloc_desc)
|
||||||
@@ -1442,8 +1523,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
||||||
char *license, __u32 kern_version, int *pfd,
|
char *license, __u32 kern_version, int *pfd)
|
||||||
__u32 func_info_cnt)
|
|
||||||
{
|
{
|
||||||
struct bpf_load_program_attr load_attr;
|
struct bpf_load_program_attr load_attr;
|
||||||
char *cp, errmsg[STRERR_BUFSIZE];
|
char *cp, errmsg[STRERR_BUFSIZE];
|
||||||
@@ -1463,8 +1543,10 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
|||||||
load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
|
load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
|
||||||
load_attr.func_info = prog->func_info;
|
load_attr.func_info = prog->func_info;
|
||||||
load_attr.func_info_rec_size = prog->func_info_rec_size;
|
load_attr.func_info_rec_size = prog->func_info_rec_size;
|
||||||
load_attr.func_info_cnt = func_info_cnt;
|
load_attr.func_info_cnt = prog->func_info_cnt;
|
||||||
|
load_attr.line_info = prog->line_info;
|
||||||
|
load_attr.line_info_rec_size = prog->line_info_rec_size;
|
||||||
|
load_attr.line_info_cnt = prog->line_info_cnt;
|
||||||
if (!load_attr.insns || !load_attr.insns_cnt)
|
if (!load_attr.insns || !load_attr.insns_cnt)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@@ -1521,14 +1603,8 @@ int
|
|||||||
bpf_program__load(struct bpf_program *prog,
|
bpf_program__load(struct bpf_program *prog,
|
||||||
char *license, __u32 kern_version)
|
char *license, __u32 kern_version)
|
||||||
{
|
{
|
||||||
__u32 func_info_cnt;
|
|
||||||
int err = 0, fd, i;
|
int err = 0, fd, i;
|
||||||
|
|
||||||
if (prog->func_info_len == 0)
|
|
||||||
func_info_cnt = 0;
|
|
||||||
else
|
|
||||||
func_info_cnt = prog->func_info_len / prog->func_info_rec_size;
|
|
||||||
|
|
||||||
if (prog->instances.nr < 0 || !prog->instances.fds) {
|
if (prog->instances.nr < 0 || !prog->instances.fds) {
|
||||||
if (prog->preprocessor) {
|
if (prog->preprocessor) {
|
||||||
pr_warning("Internal error: can't load program '%s'\n",
|
pr_warning("Internal error: can't load program '%s'\n",
|
||||||
@@ -1551,8 +1627,7 @@ bpf_program__load(struct bpf_program *prog,
|
|||||||
prog->section_name, prog->instances.nr);
|
prog->section_name, prog->instances.nr);
|
||||||
}
|
}
|
||||||
err = load_program(prog, prog->insns, prog->insns_cnt,
|
err = load_program(prog, prog->insns, prog->insns_cnt,
|
||||||
license, kern_version, &fd,
|
license, kern_version, &fd);
|
||||||
func_info_cnt);
|
|
||||||
if (!err)
|
if (!err)
|
||||||
prog->instances.fds[0] = fd;
|
prog->instances.fds[0] = fd;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1582,8 +1657,7 @@ bpf_program__load(struct bpf_program *prog,
|
|||||||
|
|
||||||
err = load_program(prog, result.new_insn_ptr,
|
err = load_program(prog, result.new_insn_ptr,
|
||||||
result.new_insn_cnt,
|
result.new_insn_cnt,
|
||||||
license, kern_version, &fd,
|
license, kern_version, &fd);
|
||||||
func_info_cnt);
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_warning("Loading the %dth instance of program '%s' failed\n",
|
pr_warning("Loading the %dth instance of program '%s' failed\n",
|
||||||
|
|||||||
13
src/libbpf.h
13
src/libbpf.h
@@ -342,6 +342,19 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
|
|||||||
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
|
||||||
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
|
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
|
||||||
|
|
||||||
|
struct bpf_prog_linfo;
|
||||||
|
struct bpf_prog_info;
|
||||||
|
|
||||||
|
LIBBPF_API void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo);
|
||||||
|
LIBBPF_API struct bpf_prog_linfo *
|
||||||
|
bpf_prog_linfo__new(const struct bpf_prog_info *info);
|
||||||
|
LIBBPF_API const struct bpf_line_info *
|
||||||
|
bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
|
||||||
|
__u64 addr, __u32 func_idx, __u32 nr_skip);
|
||||||
|
LIBBPF_API const struct bpf_line_info *
|
||||||
|
bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
|
||||||
|
__u32 insn_off, __u32 nr_skip);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
* Copyright (C) 2017 Nicira, Inc.
|
* Copyright (C) 2017 Nicira, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#undef _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user