Skip to content

Commit 71e60ea

Browse files
committed
Add support for enum64 handling in BTF parsing and struct_ops header generation.
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent 6f7c09b commit 71e60ea

5 files changed

Lines changed: 103 additions & 43 deletions

File tree

examples/sched_ext_ops.kh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,20 @@ struct sched_ext_ops {
4343
hotplug_seq: u64,
4444
name: u32,
4545
}
46+
47+
// Related kernel enums
48+
enum scx_public_consts {
49+
SCX_OPS_NAME_LEN = 128,
50+
SCX_SLICE_DFL = 20000000,
51+
SCX_SLICE_INF = 18446744073709551615,
52+
}
53+
54+
enum scx_dsq_id_flags {
55+
SCX_DSQ_FLAG_BUILTIN = 9223372036854775808,
56+
SCX_DSQ_FLAG_LOCAL_ON = 4611686018427387904,
57+
SCX_DSQ_INVALID = 9223372036854775808,
58+
SCX_DSQ_GLOBAL = 9223372036854775809,
59+
SCX_DSQ_LOCAL = 9223372036854775810,
60+
SCX_DSQ_LOCAL_ON = 13835058055282163712,
61+
SCX_DSQ_LOCAL_CPU_MASK = 4294967295,
62+
}

examples/sched_ext_simple.ks

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,6 @@ extern scx_bpf_select_cpu_dfl(p: *u8, prev_cpu: i32, wake_flags: u64, direct: *b
88
extern scx_bpf_dsq_insert(p: *u8, dsq_id: u64, slice: u64, enq_flags: u64) -> void
99
extern scx_bpf_consume(dsq_id: u64, cpu: i32, flags: u64) -> i32
1010

11-
// Kernel enums (extracted from BTF)
12-
enum scx_public_consts {
13-
SCX_OPS_NAME_LEN = 128,
14-
SCX_SLICE_DFL = 20000000,
15-
SCX_SLICE_INF = 18446744073709551615,
16-
}
17-
18-
enum scx_dsq_id_flags {
19-
SCX_DSQ_FLAG_BUILTIN = 9223372036854775808,
20-
SCX_DSQ_FLAG_LOCAL_ON = 4611686018427387904,
21-
SCX_DSQ_INVALID = 9223372036854775808,
22-
SCX_DSQ_GLOBAL = 9223372036854775809,
23-
SCX_DSQ_LOCAL = 9223372036854775810,
24-
SCX_DSQ_LOCAL_ON = 13835058055282163712,
25-
SCX_DSQ_LOCAL_CPU_MASK = 4294967295,
26-
}
27-
2811
// Simple FIFO scheduler implementation
2912
@struct_ops("sched_ext_ops")
3013
impl simple_fifo_scheduler {

src/btf_binary_parser.ml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ external btf_new_from_file : string -> btf_handle option = "btf_new_from_file_st
3535
external btf_get_nr_types : btf_handle -> int = "btf_get_nr_types_stub"
3636
external btf_type_by_id : btf_handle -> int -> (int * string * int * int * int) = "btf_type_by_id_stub"
3737

38-
external btf_type_get_members : btf_handle -> int -> (string * int) array = "btf_type_get_members_stub"
38+
external btf_type_get_members : btf_handle -> int -> (string * string) array = "btf_type_get_members_stub"
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_and_enum_names : btf_handle -> string list = "btf_extract_kernel_struct_and_enum_names_stub"
@@ -59,12 +59,13 @@ let parse_btf_file btf_path target_types =
5959
try
6060
let member_array = btf_type_get_members btf_handle union_type_id in
6161
let member_list = Array.to_list member_array in
62-
List.fold_left (fun acc (field_name, field_type_id) ->
62+
List.fold_left (fun acc (field_name, field_type_id_str) ->
6363
if field_name = "" then
6464
(* Skip anonymous members within the union to avoid infinite recursion *)
6565
acc
6666
else
6767
try
68+
let field_type_id = int_of_string field_type_id_str in
6869
let field_type = btf_resolve_type btf_handle field_type_id in
6970
(field_name, field_type) :: acc
7071
with
@@ -85,6 +86,7 @@ let parse_btf_file btf_path target_types =
8586
| 4 -> "struct"
8687
| 5 -> "union"
8788
| 6 -> "enum"
89+
| 19 -> "enum64"
8890
| _ -> "unknown"
8991
in
9092

@@ -96,8 +98,9 @@ let parse_btf_file btf_path target_types =
9698
let member_array = btf_type_get_members btf_handle i in
9799
let member_list = Array.to_list member_array in
98100
(* Resolve each member's type and handle anonymous unions *)
99-
let resolved_members = List.fold_left (fun acc (field_name, field_type_id) ->
101+
let resolved_members = List.fold_left (fun acc (field_name, field_type_id_str) ->
100102
try
103+
let field_type_id = int_of_string field_type_id_str in
101104
let field_type = btf_resolve_type btf_handle field_type_id in
102105
if field_name = "" && field_type = "union" then
103106
(* Anonymous union: extract its members and flatten them *)
@@ -120,14 +123,14 @@ let parse_btf_file btf_path target_types =
120123
Some (List.rev resolved_members)
121124
with
122125
| _ -> None
123-
) else if kind_int = 6 then (
124-
(* Enum: extract enum values *)
126+
) else if kind_int = 6 || kind_int = 19 then (
127+
(* Enum (kind 6) or Enum64 (kind 19): extract enum values *)
125128
try
126129
let member_array = btf_type_get_members btf_handle i in
127130
let member_list = Array.to_list member_array in
128-
(* For enums, second element is the value, not type_id *)
131+
(* For enums, second element is the value (now as string) *)
129132
let enum_values = List.map (fun (enum_name, enum_value) ->
130-
(enum_name, string_of_int enum_value)
133+
(enum_name, enum_value)
131134
) member_list in
132135
Some enum_values
133136
with

src/btf_parser.ml

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ let convert_btf_type_to_ks_definition btf_type =
597597
| None -> ""
598598
in
599599
sprintf "struct %s {\n%s\n}" btf_type.Btf_binary_parser.name fields
600-
| "enum" ->
600+
| "enum" | "enum64" ->
601601
let values = match btf_type.Btf_binary_parser.members with
602602
| Some members ->
603603
List.map (fun (name, value) ->
@@ -676,6 +676,15 @@ let generate_program_header ~extract_kfuncs prog_type btf_path =
676676
let enum_section = if hardcoded_enums <> "" then hardcoded_enums ^ "\n\n" else "" in
677677
sprintf "%s%s\n\n%s%s\n" header type_definitions enum_section kfunc_declarations
678678

679+
(* Get struct_ops-specific enum names to extract from BTF *)
680+
let get_struct_ops_enum_names struct_ops_name =
681+
match struct_ops_name with
682+
| "sched_ext_ops" -> [
683+
"scx_public_consts";
684+
"scx_dsq_id_flags";
685+
]
686+
| _ -> []
687+
679688
(* Generate struct_ops-specific header content using BTF *)
680689
let generate_struct_ops_header struct_ops_name btf_path =
681690
let header = sprintf {|// AUTO-GENERATED %s DEFINITIONS - DO NOT EDIT
@@ -700,7 +709,30 @@ let generate_struct_ops_header struct_ops_name btf_path =
700709
sprintf "// Warning: BTF extraction failed for %s" struct_ops_name
701710
in
702711

703-
sprintf "%s%s\n" header struct_definitions
712+
(* Extract related enums for specific struct_ops types *)
713+
let enum_definitions =
714+
let enum_names = get_struct_ops_enum_names struct_ops_name in
715+
if enum_names <> [] then
716+
try
717+
let btf_enums = Btf_binary_parser.parse_btf_file btf_path enum_names in
718+
let filtered_enums = List.filter (fun btf_type ->
719+
(btf_type.Btf_binary_parser.kind = "enum" || btf_type.Btf_binary_parser.kind = "enum64") &&
720+
List.mem btf_type.Btf_binary_parser.name enum_names
721+
) btf_enums in
722+
if filtered_enums <> [] then
723+
"\n// Related kernel enums\n" ^
724+
(List.map convert_btf_type_to_ks_definition filtered_enums |> String.concat "\n\n")
725+
else
726+
sprintf "\n// Warning: No BTF enums found for %s" struct_ops_name
727+
with
728+
| exn ->
729+
printf "Warning: Failed to extract BTF enums for %s: %s\n" struct_ops_name (Printexc.to_string exn);
730+
sprintf "\n// Warning: BTF enum extraction failed for %s" struct_ops_name
731+
else
732+
""
733+
in
734+
735+
sprintf "%s%s%s\n" header struct_definitions enum_definitions
704736

705737
(* Generate tracepoint-specific header content using BTF *)
706738
let generate_tracepoint_header category_event btf_path =

src/btf_stubs.c

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <stdio.h>
1818
#include <stdlib.h>
1919
#include <string.h>
20+
#include <inttypes.h>
2021
#include <bpf/libbpf.h>
2122
#include <bpf/btf.h>
2223
#include <caml/mlvalues.h>
@@ -149,6 +150,7 @@ value btf_type_by_id_stub(value btf_handle, value type_id) {
149150
case BTF_KIND_STRUCT:
150151
case BTF_KIND_UNION:
151152
case BTF_KIND_ENUM:
153+
case BTF_KIND_ENUM64:
152154
size = t->size;
153155
break;
154156
case BTF_KIND_PTR:
@@ -206,8 +208,8 @@ value btf_type_get_members_stub(value btf_handle, value type_id) {
206208
}
207209

208210
int kind = btf_kind(t);
209-
if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION && kind != BTF_KIND_ENUM) {
210-
/* Return empty array for non-struct/union/enum types */
211+
if (kind != BTF_KIND_STRUCT && kind != BTF_KIND_UNION && kind != BTF_KIND_ENUM && kind != BTF_KIND_ENUM64) {
212+
/* Return empty array for non-struct/union/enum/enum64 types */
211213
CAMLreturn(caml_alloc_tuple(0));
212214
}
213215

@@ -227,8 +229,30 @@ value btf_type_get_members_stub(value btf_handle, value type_id) {
227229

228230
member_tuple = caml_alloc_tuple(2);
229231
Store_field(member_tuple, 0, caml_copy_string(enum_name));
230-
/* For enums, store the value instead of type_id */
231-
Store_field(member_tuple, 1, Val_int(enums[i].val));
232+
/* For enums, convert value to string for consistency with enum64 */
233+
char value_str[16];
234+
snprintf(value_str, sizeof(value_str), "%d", enums[i].val);
235+
Store_field(member_tuple, 1, caml_copy_string(value_str));
236+
237+
Store_field(result, i, member_tuple);
238+
}
239+
} else if (kind == BTF_KIND_ENUM64) {
240+
/* Handle enum64 types - extract enum values */
241+
const struct btf_enum64 *enums = btf_enum64(t);
242+
for (int i = 0; i < vlen; i++) {
243+
const char *enum_name = btf__name_by_offset(btf, enums[i].name_off);
244+
if (!enum_name) enum_name = "";
245+
246+
member_tuple = caml_alloc_tuple(2);
247+
Store_field(member_tuple, 0, caml_copy_string(enum_name));
248+
249+
/* For enum64, combine hi32 and lo32 to get the full 64-bit value */
250+
uint64_t full_value = ((uint64_t)enums[i].val_hi32 << 32) | enums[i].val_lo32;
251+
252+
/* Convert to string to preserve full precision */
253+
char value_str[32];
254+
snprintf(value_str, sizeof(value_str), "%" PRIu64, full_value);
255+
Store_field(member_tuple, 1, caml_copy_string(value_str));
232256

233257
Store_field(result, i, member_tuple);
234258
}
@@ -241,7 +265,10 @@ value btf_type_get_members_stub(value btf_handle, value type_id) {
241265

242266
member_tuple = caml_alloc_tuple(2);
243267
Store_field(member_tuple, 0, caml_copy_string(member_name));
244-
Store_field(member_tuple, 1, Val_int(members[i].type));
268+
/* For struct/union, convert type_id to string for consistency */
269+
char type_id_str[16];
270+
snprintf(type_id_str, sizeof(type_id_str), "%u", members[i].type);
271+
Store_field(member_tuple, 1, caml_copy_string(type_id_str));
245272

246273
Store_field(result, i, member_tuple);
247274
}
@@ -305,13 +332,15 @@ static char* resolve_type_to_string(struct btf *btf, int type_id) {
305332
}
306333
case BTF_KIND_STRUCT:
307334
case BTF_KIND_UNION:
308-
case BTF_KIND_ENUM: {
335+
case BTF_KIND_ENUM:
336+
case BTF_KIND_ENUM64: {
309337
const char *name = btf__name_by_offset(btf, t->name_off);
310338
if (name && strlen(name) > 0) {
311339
return strdup(name);
312340
}
313341
return strdup(kind == BTF_KIND_STRUCT ? "struct" :
314-
kind == BTF_KIND_UNION ? "union" : "enum");
342+
kind == BTF_KIND_UNION ? "union" :
343+
kind == BTF_KIND_ENUM ? "enum" : "enum64");
315344
}
316345
default:
317346
return strdup("unknown");
@@ -477,22 +506,18 @@ value btf_resolve_type_stub(value btf_handle, value type_id) {
477506
}
478507
case BTF_KIND_STRUCT:
479508
case BTF_KIND_UNION:
480-
case BTF_KIND_ENUM: {
481-
const char *name = btf__name_by_offset(btf, t->name_off);
482-
if (name && strlen(name) > 0) {
483-
CAMLreturn(caml_copy_string(name));
484-
}
485-
/* For anonymous structs/unions */
486-
CAMLreturn(caml_copy_string(kind == BTF_KIND_STRUCT ? "struct" :
487-
kind == BTF_KIND_UNION ? "union" : "enum"));
488-
}
509+
case BTF_KIND_ENUM:
489510
case BTF_KIND_ENUM64: {
490511
const char *name = btf__name_by_offset(btf, t->name_off);
491512
if (name && strlen(name) > 0) {
492513
CAMLreturn(caml_copy_string(name));
493514
}
494-
CAMLreturn(caml_copy_string("enum64"));
515+
/* For anonymous structs/unions/enums */
516+
CAMLreturn(caml_copy_string(kind == BTF_KIND_STRUCT ? "struct" :
517+
kind == BTF_KIND_UNION ? "union" :
518+
kind == BTF_KIND_ENUM ? "enum" : "enum64"));
495519
}
520+
496521
case BTF_KIND_FWD: {
497522
const char *name = btf__name_by_offset(btf, t->name_off);
498523
if (name && strlen(name) > 0) {

0 commit comments

Comments
 (0)