iovisor / iovisor/bcc

How to parse struct data from bpf_probe_read function

Open
#2,534 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
22.7k
Forks
4.1k
Avg merge
5d 13h
Merged PRs (30d)
3

Description

I have been trying to attach uprobe to **ngx_http_process_request** function of nginx and note time taken by this function. The eBPF code looks like this:
```
#include
#include

struct val_t {
u32 pid;
char comm[TASK_COMM_LEN];
char url[80];
u64 ts;
};

struct data_t {
u32 pid;
u64 delta;
char comm[TASK_COMM_LEN];
char url[80];
};

BPF_HASH(start, u32, struct val_t);
BPF_PERF_OUTPUT(events);

int do_entry(struct pt_regs *ctx) {
if (!PT_REGS_PARM1(ctx))
return 0;
struct val_t val = {};
u32 pid = bpf_get_current_pid_tgid();
if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
bpf_probe_read(&val.url, sizeof(val.url),
(void *)PT_REGS_PARM1(ctx));
val.pid = bpf_get_current_pid_tgid();
val.ts = bpf_ktime_get_ns();
start.update(&pid, &val);
}
return 0;
}

int do_return(struct pt_regs *ctx) {
struct val_t *valp;
struct data_t data = {};
u64 delta;
u32 pid = bpf_get_current_pid_tgid();
u64 tsp = bpf_ktime_get_ns();
valp = start.lookup(&pid);
if (valp == 0)
return 0; // missed start
bpf_probe_read(&data.comm, sizeof(data.comm), valp->comm);
bpf_probe_read(&data.url, sizeof(data.url), (void *)valp->url);

data.pid = valp->pid;
data.delta = tsp - valp->ts;
events.perf_submit(ctx, &data, sizeof(data));
start.delete(&pid);
return 0;
}
```
```
bpf_probe_read(&val.url, sizeof(val.url), (void *)PT_REGS_PARM1(ctx));
```

The **bpf_probe_read** command tries to read the 1st argument of the function. I am trying to store this into a char[80] variable. This makes sense when the param is a string but as we can see in the [source code of nginx](https://github.com/nginx/nginx/blob/ecfab06cb20959219c9aadc2ef59507488e4fa99/src/http/ngx_http.h#L121), this function takes in `ngx_http_request_t` type as input argument which itself is defined as
`typedef struct ngx_http_request_s ngx_http_request_t;`
and the `ngx_http_request_s` is defined at [Link](https://github.com/nginx/nginx/blob/27b3d3dcca5fcc82350a823881f3d06161327b59/src/http/ngx_http_request.h#L371) and this struct has **uri, method,** etc as fields. I want to access those fields in my code and print them.
It currently prints **HTTP** as the 1st argument of function which is defined as signature int field at [Line 372 ](https://github.com/nginx/nginx/blob/27b3d3dcca5fcc82350a823881f3d06161327b59/src/http/ngx_http_request.h#L372) of code.

Most of the examples of eBPF show only string or int as function argument. I want to understand how to parse struct data as function argument.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with nginx/src/http/ngx_http.h at ngx_http_process_request and nginx/src/http/ngx_http_request.h at ngx_http_request_s, then compare those fields with the uprobe entry and return handlers shown in the issue. Verify how the request pointer and its nested fields are represented before deciding what a usable BCC example should demonstrate; done means the struct fields can be read and reported correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, linux, nginx
Domain
observability-sre
Issue type
Documentation
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.