Skip to content

Commit 58252b9

Browse files
committed
Implement kprobe function signature parsing and enhance context handling for new signature format. Update code generation to support flexible parameter counts and validate return types for kprobe functions. Refactor include generation to prioritize necessary headers for kprobe programs.
1 parent 769f2e8 commit 58252b9

11 files changed

Lines changed: 299 additions & 113 deletions

src/btf_parser.ml

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,9 @@ and extract_types_from_btf btf_path type_names =
150150
let get_kprobe_program_template target_function btf_path =
151151
let context_type = "*pt_regs" in
152152
let return_type = "i32" in
153-
let common_types = ["pt_regs"] in
154153

155-
(* Extract types from BTF - BTF file is required *)
156-
let extracted_types = match btf_path with
157-
| Some path when Sys.file_exists path -> extract_types_from_btf path common_types
158-
| Some path -> failwith (sprintf "BTF file not found: %s" path)
159-
| None -> failwith "BTF file path is required. Use --btf-vmlinux-path option."
160-
in
154+
(* For kprobe, we don't need to extract pt_regs since we're hiding it from users *)
155+
let extracted_types = [] in
161156

162157
(* Extract specific function signature for the target *)
163158
let function_signatures = match btf_path with
@@ -220,6 +215,55 @@ fn main() -> i32 {
220215
example_usage
221216
project_name
222217

218+
(** Parse BTF function signature to extract parameter information *)
219+
let parse_function_signature signature =
220+
(* Parse "fn(param1: type1, param2: type2, ...) -> return_type" *)
221+
try
222+
if String.length signature < 3 || not (String.sub signature 0 3 = "fn(") then
223+
failwith "Invalid function signature format"
224+
else
225+
let paren_start = 3 in
226+
let paren_end = String.index signature ')' in
227+
let params_str = String.sub signature paren_start (paren_end - paren_start) in
228+
229+
(* Parse return type *)
230+
let arrow_pos = try Some (String.index signature '>') with Not_found -> None in
231+
let return_type = match arrow_pos with
232+
| Some pos when pos > paren_end + 2 ->
233+
String.trim (String.sub signature (pos + 1) (String.length signature - pos - 1))
234+
| _ -> "i32" (* Default return type for kprobe *)
235+
in
236+
237+
(* Parse parameters *)
238+
let params = if String.trim params_str = "" then
239+
[]
240+
else
241+
let param_list = String.split_on_char ',' params_str in
242+
List.map (fun param_str ->
243+
let trimmed = String.trim param_str in
244+
let colon_pos = String.index trimmed ':' in
245+
let param_name = String.trim (String.sub trimmed 0 colon_pos) in
246+
let param_type = String.trim (String.sub trimmed (colon_pos + 1) (String.length trimmed - colon_pos - 1)) in
247+
(param_name, param_type)
248+
) param_list
249+
in
250+
251+
(params, return_type)
252+
with
253+
| exn ->
254+
printf "⚠️ Warning: Failed to parse function signature '%s': %s\n" signature (Printexc.to_string exn);
255+
([], "i32") (* Fallback *)
256+
257+
(** Generate kprobe function definition from BTF signature *)
258+
let generate_kprobe_function_from_signature func_name signature =
259+
let (params, return_type) = parse_function_signature signature in
260+
let params_str = if params = [] then
261+
""
262+
else
263+
String.concat ", " (List.map (fun (name, typ) -> sprintf "%s: %s" name typ) params)
264+
in
265+
sprintf "fn %s(%s) -> %s" func_name params_str return_type
266+
223267
(** Generate KernelScript source code from template *)
224268
let generate_kernelscript_source template project_name =
225269
let context_comment = match template.program_type with
@@ -268,21 +312,22 @@ let generate_kernelscript_source template project_name =
268312
| [] -> "0"
269313
in
270314

271-
(* Generate function signature comments for kprobe programs *)
272-
let (function_signatures_comment, target_function_name) =
315+
(* Generate function signature comments and actual function definition for kprobe programs *)
316+
let (function_signatures_comment, target_function_name, function_definition) =
273317
if template.program_type = "kprobe" && template.function_signatures <> [] then
274318
let signature_lines = List.map (fun (func_name, signature) ->
275319
sprintf "// Target function: %s -> %s" func_name signature
276320
) template.function_signatures in
277321
let comment = sprintf "\n// Target kernel function signature:\n%s\n"
278322
(String.concat "\n" signature_lines) in
279-
let first_func = match template.function_signatures with
280-
| (name, _) :: _ -> name
281-
| [] -> "target_function"
323+
let first_func, first_sig = match template.function_signatures with
324+
| (name, sig_str) :: _ -> (name, sig_str)
325+
| [] -> ("target_function", "fn() -> i32")
282326
in
283-
(comment, first_func)
327+
let func_def = generate_kprobe_function_from_signature first_func first_sig in
328+
(comment, first_func, func_def)
284329
else
285-
("", "target_function")
330+
("", "target_function", sprintf "fn %s_handler(ctx: %s) -> %s" project_name template.context_type template.return_type)
286331
in
287332

288333
(* Customize attach call for kprobe *)
@@ -293,20 +338,22 @@ let generate_kernelscript_source template project_name =
293338
" // TODO: Update interface name and attachment parameters"
294339
in
295340

341+
let function_name = if template.program_type = "kprobe" then target_function_name else sprintf "%s_handler" project_name in
342+
296343
sprintf {|%s
297344
// Generated by KernelScript compiler with direct BTF parsing
298345
%s
299346
%s
300347

301348
@%s
302-
fn %s_handler(ctx: %s) -> %s {
349+
%s {
303350
// TODO: Implement your %s logic here
304351

305352
return %s
306353
}
307354

308355
fn main() -> i32 {
309-
var prog = load(%s_handler)
356+
var prog = load(%s)
310357

311358
%s
312359
var result = attach(prog, "%s", 0)
@@ -320,4 +367,4 @@ fn main() -> i32 {
320367

321368
return 0
322369
}
323-
|} context_comment function_signatures_comment type_definitions template.program_type project_name template.context_type template.return_type template.program_type sample_return project_name attach_comment attach_target template.program_type template.program_type
370+
|} context_comment function_signatures_comment type_definitions template.program_type function_definition template.program_type sample_return function_name attach_comment attach_target template.program_type template.program_type

src/btf_stubs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ static char* resolve_type_to_string(struct btf *btf, int type_id) {
256256
if (kind == BTF_KIND_PTR) {
257257
const struct btf_type *target = btf__type_by_id(btf, t->type);
258258
if (target && btf_kind(target) == BTF_KIND_INT && target->size == 1) {
259-
return strdup("str");
259+
return strdup("*u8"); /* Use *u8 for char* to avoid str parsing issues */
260260
}
261261
return strdup("*u8");
262262
}
@@ -371,7 +371,7 @@ value btf_resolve_type_stub(value btf_handle, value type_id) {
371371
}
372372
/* Check if this points to char (string) */
373373
if (target && btf_kind(target) == BTF_KIND_INT && target->size == 1) {
374-
CAMLreturn(caml_copy_string("str"));
374+
CAMLreturn(caml_copy_string("*u8")); /* Use *u8 for char* to avoid str parsing issues */
375375
}
376376
/* Other pointer types */
377377
CAMLreturn(caml_copy_string("*u8"));
@@ -520,7 +520,7 @@ value btf_extract_function_signatures_stub(value btf_handle, value function_name
520520
temp = Field(temp, 1);
521521
}
522522

523-
char **target_functions = malloc(func_count * sizeof(char*));
523+
const char **target_functions = malloc(func_count * sizeof(const char*));
524524
temp = function_names;
525525
for (int i = 0; i < func_count; i++) {
526526
target_functions[i] = String_val(Field(temp, 0));

src/context/kprobe_codegen.ml

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,59 @@ let kprobe_field_mappings = [
9494
});
9595
]
9696

97-
(** Generate kprobe-specific includes *)
97+
(** Dynamic kprobe parameter mappings - populated during compilation based on function signature *)
98+
let kprobe_parameter_mappings = ref []
99+
100+
(** Register kprobe parameter mappings for a specific function *)
101+
let register_kprobe_parameter_mappings func_name parameters =
102+
let param_mappings = List.mapi (fun i (param_name, param_type) ->
103+
let parm_macro = match i with
104+
| 0 -> "PT_REGS_PARM1"
105+
| 1 -> "PT_REGS_PARM2"
106+
| 2 -> "PT_REGS_PARM3"
107+
| 3 -> "PT_REGS_PARM4"
108+
| 4 -> "PT_REGS_PARM5"
109+
| 5 -> "PT_REGS_PARM6"
110+
| _ -> failwith (sprintf "Too many parameters for kprobe function %s (max 6)" func_name)
111+
in
112+
(param_name, {
113+
field_name = param_name;
114+
c_expression = (fun ctx_var -> sprintf "%s(%s)" parm_macro ctx_var);
115+
requires_cast = false;
116+
field_type = param_type;
117+
})
118+
) parameters in
119+
kprobe_parameter_mappings := param_mappings
120+
121+
(** Clear kprobe parameter mappings *)
122+
let clear_kprobe_parameter_mappings () =
123+
kprobe_parameter_mappings := []
124+
125+
(** Generate kprobe-specific includes with architecture definition at the top *)
98126
let generate_kprobe_includes () = [
127+
"/* Target architecture definition required for PT_REGS_PARM* macros */";
128+
"#ifndef __TARGET_ARCH_x86";
129+
"#define __TARGET_ARCH_x86";
130+
"#endif";
131+
"";
99132
"#include <linux/types.h>";
100-
"#include <linux/bpf.h>";
101-
"#include <linux/ptrace.h>";
102133
"#include <bpf/bpf_tracing.h>";
103-
"#include <bpf/bpf_helpers.h>";
134+
"#include <linux/ptrace.h>";
104135
]
105136

106137
(** Generate field access for kprobe context *)
107138
let generate_kprobe_field_access ctx_var field_name =
108139
try
109-
let (_, field_access) = List.find (fun (name, _) -> name = field_name) kprobe_field_mappings in
140+
(* First check dynamic parameter mappings *)
141+
let (_, field_access) = List.find (fun (name, _) -> name = field_name) !kprobe_parameter_mappings in
110142
field_access.c_expression ctx_var
111143
with Not_found ->
112-
failwith ("Unknown kprobe context field: " ^ field_name)
144+
try
145+
(* Fallback to static register mappings *)
146+
let (_, field_access) = List.find (fun (name, _) -> name = field_name) kprobe_field_mappings in
147+
field_access.c_expression ctx_var
148+
with Not_found ->
149+
failwith ("Unknown kprobe context field: " ^ field_name)
113150

114151
(** Map kprobe return constants *)
115152
let map_kprobe_action_constant = function

0 commit comments

Comments
 (0)