Skip to content

Commit fcff065

Browse files
committed
Add kfunc extraction functionality to BTF parser.
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent 6699975 commit fcff065

File tree

7 files changed

+199
-27
lines changed

7 files changed

+199
-27
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ kernelscript init probe/sys_read my_tracer
255255
# Create project with custom BTF path
256256
kernelscript init --btf-vmlinux-path /custom/path/vmlinux xdp my_project
257257

258+
# Create XDP project with kfuncs extracted
259+
kernelscript init --kfuncs xdp my_packet_filter
260+
258261
# Create struct_ops project
259262
kernelscript init tcp_congestion_ops my_congestion_control
260263
```

src/btf_binary_parser.ml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ external btf_type_get_members : btf_handle -> int -> (string * int) array = "btf
3939
external btf_resolve_type : btf_handle -> int -> string = "btf_resolve_type_stub"
4040
external btf_extract_function_signatures : btf_handle -> string list -> (string * string) list = "btf_extract_function_signatures_stub"
4141
external btf_extract_kernel_struct_names : btf_handle -> string list = "btf_extract_kernel_struct_names_stub"
42+
external btf_extract_kfuncs : btf_handle -> (string * string) list = "btf_extract_kfuncs_stub"
4243
external btf_free : btf_handle -> unit = "btf_free_stub"
4344

4445
(** Parse BTF file and extract requested types using libbpf *)
@@ -195,4 +196,30 @@ let extract_all_kernel_struct_names btf_path =
195196
btf_free btf_handle;
196197
struct_names
197198
with
198-
| _ -> []
199+
| _ -> []
200+
201+
(** Extract kfuncs from BTF file using DECL_TAG annotations *)
202+
let extract_kfuncs_from_btf btf_path =
203+
try
204+
printf "Extracting kfuncs from BTF file: %s\n" btf_path;
205+
206+
match btf_new_from_file btf_path with
207+
| None -> (
208+
printf "Error: Failed to open BTF file %s\n" btf_path;
209+
[]
210+
)
211+
| Some btf_handle -> (
212+
let kfuncs = btf_extract_kfuncs btf_handle in
213+
btf_free btf_handle;
214+
215+
printf "Successfully extracted %d kfuncs\n" (List.length kfuncs);
216+
List.iter (fun (name, sig_str) ->
217+
printf " Kfunc: %s -> %s\n" name sig_str
218+
) kfuncs;
219+
220+
kfuncs
221+
)
222+
with
223+
| exn ->
224+
printf "Error extracting kfuncs from BTF file %s: %s\n" btf_path (Printexc.to_string exn);
225+
[]

src/btf_binary_parser.mli

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ val extract_kernel_function_signatures : string -> string list -> (string * stri
3939
(** Extract all kernel-defined struct names from BTF file.
4040
@param btf_path Path to the binary BTF file
4141
@return List of kernel struct names *)
42-
val extract_all_kernel_struct_names : string -> string list
42+
val extract_all_kernel_struct_names : string -> string list
43+
44+
(** Extract kfuncs from BTF file using DECL_TAG annotations.
45+
@param btf_path Path to the binary BTF file
46+
@return List of (function_name, signature) pairs for functions tagged with "bpf_kfunc" *)
47+
val extract_kfuncs_from_btf : string -> (string * string) list

src/btf_parser.ml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,21 @@ let extract_struct_ops_definitions btf_path struct_ops_names =
207207
failwith "BTF file path is required for struct_ops extraction. Use --btf-vmlinux-path option."
208208

209209
(** Generate struct_ops template with BTF extraction *)
210-
let generate_struct_ops_template btf_path struct_ops_names project_name =
210+
let generate_struct_ops_template ?include_kfuncs btf_path struct_ops_names project_name =
211211
let struct_ops_definitions = extract_struct_ops_definitions btf_path struct_ops_names in
212212
let struct_ops_code = String.concat "\n\n" struct_ops_definitions in
213213

214214
let example_usage = List.map (fun name ->
215215
Struct_ops_registry.generate_struct_ops_usage_example name
216216
) struct_ops_names |> String.concat "\n\n" in
217217

218+
let include_line = match include_kfuncs with
219+
| Some kh_filename -> sprintf "\ninclude \"%s\"\n" kh_filename
220+
| None -> ""
221+
in
222+
218223
sprintf {|// Generated struct_ops template for %s
219-
// Extracted from BTF: %s
224+
// Extracted from BTF: %s%s
220225

221226
%s
222227

@@ -230,6 +235,7 @@ fn main() -> i32 {
230235
(match btf_path with
231236
| Some path -> sprintf "definitions from %s" path
232237
| None -> "placeholder definitions")
238+
include_line
233239
struct_ops_code
234240
example_usage
235241
project_name
@@ -284,7 +290,7 @@ let generate_kprobe_function_from_signature func_name signature =
284290
sprintf "fn %s(%s) -> %s" func_name params_str return_type
285291

286292
(** Generate KernelScript source code from template *)
287-
let generate_kernelscript_source ?extra_param template project_name =
293+
let generate_kernelscript_source ?extra_param ?include_kfuncs template project_name =
288294
let context_comment = match template.program_type with
289295
| "xdp" -> "// XDP (eXpress Data Path) program for high-performance packet processing"
290296
| "tc" -> "// TC (Traffic Control) program for network traffic shaping and filtering"
@@ -410,8 +416,13 @@ let generate_kernelscript_source ?extra_param template project_name =
410416
else template.program_type
411417
in
412418

419+
let include_line = match include_kfuncs with
420+
| Some kh_filename -> sprintf "\ninclude \"%s\"\n" kh_filename
421+
| None -> ""
422+
in
423+
413424
sprintf {|%s
414-
// Generated by KernelScript compiler with direct BTF parsing
425+
// Generated by KernelScript compiler with direct BTF parsing%s
415426
%s
416427
%s
417428

@@ -437,4 +448,4 @@ fn main() -> i32 {
437448

438449
return 0
439450
}
440-
|} context_comment function_signatures_comment type_definitions attribute_line function_definition template.program_type sample_return function_name attach_comment attach_target program_description program_description
451+
|} context_comment include_line function_signatures_comment type_definitions attribute_line function_definition template.program_type sample_return function_name attach_comment attach_target program_description program_description

src/btf_parser.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ val is_well_known_kernel_type : ?btf_path:string -> string -> bool
4949
val extract_struct_ops_definitions : string option -> string list -> string list
5050

5151
(** Generate struct_ops template with BTF extraction *)
52-
val generate_struct_ops_template : string option -> string list -> string -> string
52+
val generate_struct_ops_template : ?include_kfuncs:string -> string option -> string list -> string -> string
5353

5454
(** Generate KernelScript source code from template *)
55-
val generate_kernelscript_source : ?extra_param:string -> program_template -> string -> string
55+
val generate_kernelscript_source : ?extra_param:string -> ?include_kfuncs:string -> program_template -> string -> string

src/btf_stubs.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,64 @@ value btf_extract_kernel_struct_names_stub(value btf_handle) {
631631
CAMLreturn(result);
632632
}
633633

634+
/* Extract kfuncs from BTF using DECL_TAG annotations */
635+
value btf_extract_kfuncs_stub(value btf_handle) {
636+
CAMLparam1(btf_handle);
637+
CAMLlocal3(result_list, current, tuple);
638+
639+
struct btf *btf = btf_of_value(btf_handle);
640+
if (!btf) {
641+
CAMLreturn(Val_emptylist);
642+
}
643+
644+
result_list = Val_emptylist;
645+
int nr_types = btf__type_cnt(btf);
646+
647+
/* First pass: find all DECL_TAG types that reference "bpf_kfunc" */
648+
for (int i = 1; i < nr_types; i++) {
649+
const struct btf_type *t = btf__type_by_id(btf, i);
650+
if (!t) continue;
651+
652+
int kind = btf_kind(t);
653+
654+
if (kind == BTF_KIND_DECL_TAG) {
655+
const char *tag_name = btf__name_by_offset(btf, t->name_off);
656+
if (tag_name && strcmp(tag_name, "bpf_kfunc") == 0) {
657+
/* This is a bpf_kfunc tag, get the function it references */
658+
int target_id = t->type;
659+
const struct btf_type *target_func = btf__type_by_id(btf, target_id);
660+
661+
if (target_func && btf_kind(target_func) == BTF_KIND_FUNC) {
662+
const char *func_name = btf__name_by_offset(btf, target_func->name_off);
663+
if (!func_name) continue;
664+
665+
/* Get the function prototype */
666+
const struct btf_type *func_proto = btf__type_by_id(btf, target_func->type);
667+
if (func_proto && btf_kind(func_proto) == BTF_KIND_FUNC_PROTO) {
668+
/* Extract function signature */
669+
char *signature = format_function_prototype(btf, func_proto);
670+
671+
/* Create tuple (function_name, signature) */
672+
tuple = caml_alloc_tuple(2);
673+
Store_field(tuple, 0, caml_copy_string(func_name));
674+
Store_field(tuple, 1, caml_copy_string(signature));
675+
676+
/* Add to result list */
677+
current = caml_alloc(2, 0);
678+
Store_field(current, 0, tuple);
679+
Store_field(current, 1, result_list);
680+
result_list = current;
681+
682+
free(signature);
683+
}
684+
}
685+
}
686+
}
687+
}
688+
689+
CAMLreturn(result_list);
690+
}
691+
634692
/* Free BTF handle */
635693
value btf_free_stub(value btf_handle) {
636694
CAMLparam1(btf_handle);

0 commit comments

Comments
 (0)