Carl 10 月之前
父节点
当前提交
d9fcd74e8d

+ 130 - 0
example/tracing/biolatpcts.php

@@ -0,0 +1,130 @@
+<?php
+$bpf_source = <<<EOT
+#include <linux/blkdev.h>
+#include <linux/time64.h>
+
+BPF_PERCPU_ARRAY(lat_100ms, u64, 100);
+BPF_PERCPU_ARRAY(lat_1ms, u64, 100);
+BPF_PERCPU_ARRAY(lat_10us, u64, 100);
+
+RAW_TRACEPOINT_PROBE(block_rq_complete)
+{
+        // TP_PROTO(struct request *rq, blk_status_t error, unsigned int nr_bytes)
+        struct request *rq = (void *)ctx->args[0];
+        unsigned int cmd_flags;
+        u64 dur;
+        size_t base, slot;
+
+        if (!rq->io_start_time_ns)
+                return 0;
+
+        dur = bpf_ktime_get_ns() - rq->io_start_time_ns;
+
+        slot = min_t(size_t, div_u64(dur, 100 * NSEC_PER_MSEC), 99);
+        lat_100ms.increment(slot);
+        if (slot)
+                return 0;
+
+        slot = min_t(size_t, div_u64(dur, NSEC_PER_MSEC), 99);
+        lat_1ms.increment(slot);
+        if (slot)
+                return 0;
+
+        slot = min_t(size_t, div_u64(dur, 10 * NSEC_PER_USEC), 99);
+        lat_10us.increment(slot);
+        return 0;
+}
+EOT;
+
+$ebpf = new Ebpf($bpf_source);
+
+$cur_lat_100ms = $ebpf->lat_100ms;
+$cur_lat_1ms =$ebpf->lat_1ms;
+$cur_lat_10us = $ebpf->lat_10us;
+
+
+$last_lat_100ms = array_fill(0, 100, 0);
+$last_lat_1ms = array_fill(0, 100, 0);
+$last_lat_10us = array_fill(0, 100, 0);
+
+$lat_100ms = array_fill(0, 100, 0);
+$lat_1ms = array_fill(0, 100, 0);
+$lat_10us = array_fill(0, 100, 0);
+
+function find_pct($req, $total, &$slots, $idx, $counted) {
+    while ($idx > 0) {
+        $idx--;
+        if ($slots[$idx] > 0) {
+            $counted += $slots[$idx];
+            if (($counted / $total) * 100 >= 100 - $req) {
+                break;
+            }
+        }
+    }
+    return [$idx, $counted];
+}
+
+function calc_lat_pct($req_pcts, $total, &$lat_100ms, &$lat_1ms, &$lat_10us) {
+    $pcts = array_fill(0, count($req_pcts), 0);
+
+    if ($total == 0) {
+        return $pcts;
+    }
+
+    $data = [[100 * 1000, &$lat_100ms], [1000, &$lat_1ms], [10, &$lat_10us]];
+    $data_sel = 0;
+    $idx = 100;
+    $counted = 0;
+
+    for ($pct_idx = count($req_pcts) - 1; $pct_idx >= 0; $pct_idx--) {
+        $req = floatval($req_pcts[$pct_idx]);
+        while (true) {
+            $last_counted = $counted;
+            [$gran, $slots] = $data[$data_sel];
+            [$idx, $counted] = find_pct($req, $total, $slots, $idx, $counted);
+            if ($idx > 0 || $data_sel == count($data) - 1) {
+                break;
+            }
+            $counted = $last_counted;
+            $data_sel++;
+            $idx = 100;
+        }
+
+        $pcts[$pct_idx] = $gran * $idx + $gran / 2;
+    }
+
+    return $pcts;
+}
+
+echo "Block I/O latency percentile example.\n";
+
+
+while (true) {
+    sleep(3);
+
+    $lat_total = 0;
+
+    for ($i = 0; $i < 100; $i++) {
+        $v = $cur_lat_100ms->sum_value($i);
+        $lat_100ms[$i] = max($v - $last_lat_100ms[$i], 0);
+        $last_lat_100ms[$i] = $v;
+
+        $v =  $cur_lat_1ms->sum_value($i);
+        $lat_1ms[$i] = max($v - $last_lat_1ms[$i], 0);
+        $last_lat_1ms[$i] = $v;
+
+        $v = $cur_lat_10us->sum_value($i);
+        $lat_10us[$i] = max($v - $last_lat_10us[$i], 0);
+        $last_lat_10us[$i] = $v;
+
+        $lat_total += $lat_100ms[$i];
+    }
+
+    $target_pcts = [50, 75, 90, 99];
+    $pcts = calc_lat_pct($target_pcts, $lat_total, $lat_100ms, $lat_1ms, $lat_10us);
+
+    for ($i = 0; $i < count($target_pcts); $i++) {
+        echo "p" . $target_pcts[$i] . "=" . intval($pcts[$i]) . "us ";
+    }
+    echo PHP_EOL;
+}

+ 87 - 0
example/tracing/dddos.php

@@ -0,0 +1,87 @@
+<?php
+$prog = <<<EOT
+#include <linux/skbuff.h>
+#include <uapi/linux/ip.h>
+
+#define MAX_NB_PACKETS 1000
+#define LEGAL_DIFF_TIMESTAMP_PACKETS 1000000
+
+BPF_HASH(rcv_packets);
+
+struct detectionPackets {
+    u64 nb_ddos_packets;
+};
+
+BPF_PERF_OUTPUT(events);
+
+int detect_ddos(struct pt_regs *ctx, void *skb){
+    struct detectionPackets detectionPacket = {};
+
+    // Used to count number of received packets
+    u64 rcv_packets_nb_index = 0, rcv_packets_nb_inter=1, *rcv_packets_nb_ptr;
+
+    // Used to measure elapsed time between 2 successive received packets
+    u64 rcv_packets_ts_index = 1, rcv_packets_ts_inter=0, *rcv_packets_ts_ptr;
+
+    /* The algorithm analyses packets received by ip_rcv function
+    * and measures the difference in reception time between each packet.
+    * DDOS flooders send millions of packets such that difference of
+    * timestamp between 2 successive packets is so small
+    * (which is not like regular applications behaviour).
+    * This script looks for this difference in time and if it sees
+    * more than MAX_NB_PACKETS successive packets with a difference
+    * of timestamp between each one of them less than
+    * LEGAL_DIFF_TIMESTAMP_PACKETS ns,
+    * ------------------ It Triggers an ALERT -----------------
+    * Those settings must be adapted depending on regular network traffic
+    * -------------------------------------------------------------------
+    * Important: this is a rudimentary intrusion detection system, one can
+    * test a real case attack using hping3. However; if regular network
+    * traffic increases above predefined detection settings, a false
+    * positive alert will be triggered (an example would be the
+    * case of large file downloads).
+    */
+    rcv_packets_nb_ptr = rcv_packets.lookup(&rcv_packets_nb_index);
+    rcv_packets_ts_ptr = rcv_packets.lookup(&rcv_packets_ts_index);
+    if(rcv_packets_nb_ptr != 0 && rcv_packets_ts_ptr != 0){
+        rcv_packets_nb_inter = *rcv_packets_nb_ptr;
+        rcv_packets_ts_inter = bpf_ktime_get_ns() - *rcv_packets_ts_ptr;
+        if(rcv_packets_ts_inter < LEGAL_DIFF_TIMESTAMP_PACKETS){
+            rcv_packets_nb_inter++;
+        } else {
+            rcv_packets_nb_inter = 0;
+        }
+        if(rcv_packets_nb_inter > MAX_NB_PACKETS){
+            detectionPacket.nb_ddos_packets = rcv_packets_nb_inter;
+            events.perf_submit(ctx, &detectionPacket, sizeof(detectionPacket));
+        }
+    }
+    rcv_packets_ts_inter = bpf_ktime_get_ns();
+    rcv_packets.update(&rcv_packets_nb_index, &rcv_packets_nb_inter);
+    rcv_packets.update(&rcv_packets_ts_index, &rcv_packets_ts_inter);
+    return 0;
+}
+EOT;
+$b    = new Ebpf($prog);
+
+$b->attach_kprobe("ip_rcv", "detect_ddos");
+
+echo "DDOS detector started ... Hit Ctrl-C to end!\n";
+
+echo sprintf("%-26s %-10s\n", "TIME(s)", "MESSAGE");
+
+function trigger_alert_event($ctx, $data, $size)
+{
+    $event = unpack("Qnb_ddos_packets", $data);
+    echo sprintf("%-26s %s %ld\n", date("Y-m-d H:i:s"), "DDOS Attack => nb of packets up to now: ", $event['nb_ddos_packets']);
+}
+
+$b->events->open_perf_buffer("trigger_alert_event");
+
+while (true) {
+    try {
+        $b->perf_buffer_poll();
+    } catch (Exception $e) {
+        exit;
+    }
+}

+ 22 - 0
example/tracing/hello_fields.php

@@ -0,0 +1,22 @@
+<?php
+$prog = <<<EOT
+int hello(void *ctx) {
+    bpf_trace_printk("Hello, World!\\n");
+    return 0;
+}
+EOT;
+# load BPF program
+$ebpf = new Ebpf($prog);
+$ebpf->attach_kprobe($ebpf->get_syscall_fnname("clone"),"hello");
+# header
+printf("%-18s %-16s %-6s %s\n", "TIME(s)", "COMM", "PID", "MESSAGE");
+# format output
+while (true) {
+    try {
+        list($task, $pid, $cpu, $flags, $ts, $msg) =$ebpf->trace_fields();
+        printf("%-18.9f %-16s %-6d %s\n", $ts, $task, $pid, $msg);
+        flush();
+    } catch (Exception $e) {
+        continue;
+    }
+}

+ 54 - 0
example/tracing/hello_perf_output.php

@@ -0,0 +1,54 @@
+<?php
+$prog = <<<EOT
+#include <linux/sched.h>
+
+// define output data structure in C
+struct data_t {
+    u32 pid;
+    u64 ts;
+    char comm[TASK_COMM_LEN];
+};
+BPF_PERF_OUTPUT(events);
+
+int hello(struct pt_regs *ctx) {
+    struct data_t data = {};
+
+    data.pid = bpf_get_current_pid_tgid();
+    data.ts = bpf_ktime_get_ns();
+    bpf_get_current_comm(&data.comm, sizeof(data.comm));
+
+    events.perf_submit(ctx, &data, sizeof(data));
+
+    return 0;
+}
+EOT;
+
+# load BPF program
+$b    = new Ebpf($prog);
+$b->attach_kprobe($b->get_syscall_fnname("clone"), "hello");
+
+# header
+printf("%-18s %-16s %-6s %s\n", "TIME(s)", "COMM", "PID", "MESSAGE");
+
+# process event
+$start = 0;
+function print_event($cpu, $data, $size) {
+    global $start;
+    $event = unpack("Qpid/Qts/A16comm", $data);
+    if ($start == 0) {
+        $start = $event['ts'];
+    }
+    $time_s = ($event['ts'] - $start) / 1000000000.0;
+    printf("%-18.9f %-16s %-6d %s\n", $time_s, $event['comm'], $event['pid'], "Hello, perf_output!");
+}
+
+# loop with callback to print_event
+$b->events->open_perf_buffer("print_event");
+
+while (true) {
+    try {
+        $b->perf_buffer_poll();
+    } catch (Exception $e) {
+        exit();
+    }
+}

+ 62 - 0
example/tracing/hello_perf_output_using_ns.php

@@ -0,0 +1,62 @@
+<?php
+$prog = <<<EOT
+#include <linux/sched.h>
+
+// define output data structure in C
+struct data_t {
+    u32 pid;
+    u64 ts;
+    char comm[TASK_COMM_LEN];
+};
+BPF_PERF_OUTPUT(events);
+
+int hello(struct pt_regs *ctx) {
+    struct data_t data = {};
+    struct bpf_pidns_info ns = {};
+
+    if(bpf_get_ns_current_pid_tgid(DEV, INO, &ns, sizeof(struct bpf_pidns_info)))
+    return 0;
+    data.pid = ns.pid;
+    data.ts = bpf_ktime_get_ns();
+    bpf_get_current_comm(&data.comm, sizeof(data.comm));
+
+    events.perf_submit(ctx, &data, sizeof(data));
+
+    return 0;
+}
+EOT;
+$stat = stat("/proc/self/ns/pid");
+$dev = $stat["dev"];
+$ino = $stat["ino"];
+$prog = str_replace("DEV", strval($dev), $prog);
+$prog = str_replace("INO", strval($ino), $prog);
+
+# load BPF program
+$b    = new Ebpf($prog);
+$b->attach_kprobe($b->get_syscall_fnname("clone"), "hello");
+
+# header
+printf("%-18s %-16s %-6s %s\n", "TIME(s)", "COMM", "PID", "MESSAGE");
+
+# process event
+$start = 0;
+function print_event($cpu, $data, $size) {
+    global $start;
+    $event = unpack("Qpid/Qts/A16comm", $data);
+    if ($start == 0) {
+        $start = $event['ts'];
+    }
+    $time_s = ($event['ts'] - $start) / 1000000000.0;
+    printf("%-18.9f %-16s %-6d %s\n", $time_s, $event['comm'], $event['pid'], "Hello, perf_output!");
+}
+
+# loop with callback to print_event
+$b->events->open_perf_buffer("print_event");
+
+while (true) {
+    try {
+        $b->perf_buffer_poll();
+    } catch (Exception $e) {
+        exit();
+    }
+}

+ 54 - 0
example/tracing/kvm_hypercall.php

@@ -0,0 +1,54 @@
+<?php
+$prog = <<<EOT
+#define EXIT_REASON 18
+BPF_HASH(start, u8, u8);
+
+TRACEPOINT_PROBE(kvm, kvm_exit) {
+    u8 e = EXIT_REASON;
+    u8 one = 1;
+    if (args->exit_reason == EXIT_REASON) {
+        bpf_trace_printk("KVM_EXIT exit_reason : %d\\n", args->exit_reason);
+        start.update(&e, &one);
+    }
+    return 0;
+}
+
+TRACEPOINT_PROBE(kvm, kvm_entry) {
+    u8 e = EXIT_REASON;
+    u8 zero = 0;
+    u8 *s = start.lookup(&e);
+    if (s != NULL && *s == 1) {
+        bpf_trace_printk("KVM_ENTRY vcpu_id : %u\\n", args->vcpu_id);
+        start.update(&e, &zero);
+    }
+    return 0;
+}
+
+TRACEPOINT_PROBE(kvm, kvm_hypercall) {
+    u8 e = EXIT_REASON;
+    u8 zero = 0;
+    u8 *s = start.lookup(&e);
+    if (s != NULL && *s == 1) {
+        bpf_trace_printk("HYPERCALL nr : %d\\n", args->nr);
+    }
+    return 0;
+};
+EOT;
+
+
+# load BPF program
+$b = new Ebpf($prog);
+
+# header
+printf("%-18s %-16s %-6s %s\n", "TIME(s)", "COMM", "PID", "EVENT");
+
+# format output
+while (true) {
+    try {
+        list($task, $pid, $cpu, $flags, $ts, $msg) = $b->trace_fields();
+        printf("%-18.9f %-16s %-6d %s\n", $ts, $task, $pid, $msg);
+        flush();
+    } catch (Exception $e) {
+        exit();
+    }
+}

+ 67 - 0
example/tracing/mallocstacks.php

@@ -0,0 +1,67 @@
+<?php
+if ($argc < 2) {
+    echo "USAGE: mallocstacks PID [NUM_STACKS=1024]\n";
+    exit(1);
+}
+$pid    = (int)$argv[1];
+$stacks = ($argc == 3 && is_numeric($argv[2]) && (int)$argv[2] > 0) ? $argv[2] : "1024";
+
+$bpf_text = <<<EOT
+#include <uapi/linux/ptrace.h>
+
+BPF_HASH(calls, int);
+BPF_STACK_TRACE(stack_traces, {$stacks});
+
+int alloc_enter(struct pt_regs *ctx, size_t size) {
+    int key = stack_traces.get_stackid(ctx, BPF_F_USER_STACK);
+    if (key < 0)
+        return 0;
+
+    u64 zero = 0, *val;
+    val = calls.lookup_or_try_init(&key, &zero);
+    if (val) {
+      (*val) += size;
+    }
+    return 0;
+};
+EOT;
+
+$ebpf = new Ebpf($bpf_text);
+$ebpf->attach_uprobe("c", "malloc", "alloc_enter", ["pid" => $pid]);
+echo "Attaching to malloc in pid {$pid}, Ctrl+C to quit.\n";
+
+pcntl_signal(SIGINT, "signalHandler");
+
+pcntl_async_signals(true);
+
+# sleep until Ctrl-C
+while (true) {
+    sleep(99999999);
+}
+
+function signalHandler($signo)
+{
+    global $ebpf;
+    global $pid;
+    switch ($signo) {
+        case SIGINT:
+            $calls        = $ebpf->get_table("calls");
+            $stack_traces = $ebpf->get_table("stack_traces");
+
+            $calls_vals = $calls->values();
+            arsort($calls_vals);
+
+            foreach ($calls_vals as $key => $value) {
+                printf("%d bytes allocated at:\n", $value);
+
+                if ($key > 0) {
+                    $a = $stack_traces->values($key, $pid);
+                    foreach ($a as $addr) {
+                        printf("\t%s\n", $addr);
+                    }
+                    printf("    %d\n\n", $value);
+                }
+            }
+            exit(0);
+    }
+}

+ 1 - 1
example/tracing/trace_perf_output.php

@@ -30,7 +30,7 @@ EOT;
 $ebpf = new Ebpf($prog);
 $event_name = $ebpf->get_syscall_fnname("clone");
 $ebpf->attach_kprobe($event_name,"do_sys_clone");
-$ebpf->perf_event("events")->open_perf_buffer("cb");
+$ebpf->events->open_perf_buffer("trigger_alert_event");
 echo("Tracing... Hit Ctrl-C to end.\n");
 while (true) {
     try {

+ 157 - 42
main.cpp

@@ -1,20 +1,22 @@
 #include <iostream>
-#include <phpcpp.h>
 #include <fstream>
-#include "bcc_common.h"
-#include "bpf_module.h"
-#include "libbpf.h"
-#include "BPF.h"
 #include <csignal>
-#include <atomic>
 #include <sstream>
 #include <utility>
 #include <vector>
-#include "table.cpp"
+#include <unordered_set>
+#include <regex>
+#include <phpcpp.h>
+#include "bcc_common.h"
+#include "bpf_module.h"
+#include "libbpf.h"
+#include <BPF.h>
+#include "table.h"
 
-constexpr const char *TRACE_PIPE_PATH = "/sys/kernel/debug/tracing/trace_pipe";
+#define TRACE_PIPE_PATH "/sys/kernel/debug/tracing/trace_pipe"
+
+#define DEBUGFS "/sys/kernel/debug"
 
-// Php::out << "Value of fn: " << fnn << std::endl;
 
 const std::vector<std::string> syscall_prefixes = {
 		"sys_",
@@ -88,35 +90,135 @@ public:
 
 	Php::Value __get(const Php::Value &name) {
 		int from_attr = 1;
-		auto res = get_table_cls(name, from_attr);  // 这里传递 std::vector<Php::Value>
+		auto res = get_table_cls(name, from_attr);
 		if (!res.isObject()) {
 			return Php::Base::__get(name);
 		} else {
 			return res;
 		}
+	}
+
+	std::unordered_set<std::string> get_kprobe_functions(const std::string &event_re) {
+		std::unordered_set<std::string> blacklist;
+		std::unordered_set<std::string> avail_filter;
+		std::unordered_set<std::string> fns;
+
+		std::string blacklist_file = std::string(DEBUGFS) + "/kprobes/blacklist";
+		std::ifstream blacklist_f(blacklist_file);
+		if (blacklist_f.is_open()) {
+			std::string line;
+			while (std::getline(blacklist_f, line)) {
+				std::istringstream iss(line);
+				std::string addr, func_name;
+				if (iss >> addr >> func_name) {
+					blacklist.insert(func_name);
+				}
+			}
+			blacklist_f.close();
+		}
+
+		std::string avail_filter_file = std::string(DEBUGFS) + "/tracing/available_filter_functions";
+		std::ifstream avail_filter_f(avail_filter_file);
+		if (avail_filter_f.is_open()) {
+			std::string line;
+			while (std::getline(avail_filter_f, line)) {
+				std::istringstream iss(line);
+				std::string func_name;
+				if (iss >> func_name) {
+					avail_filter.insert(func_name);
+				}
+			}
+			avail_filter_f.close();
+		}
+
+		std::ifstream kallsyms_f("/proc/kallsyms");
+		if (!kallsyms_f.is_open()) {
+			std::cerr << "Failed to open /proc/kallsyms\n";
+			return fns;
+		}
+
+		std::string line;
+		bool in_init_section = false;
+		bool in_irq_section = false;
+		std::regex cold_regex(".*\\.cold(\\.\\d+)?$");
+
+		while (std::getline(kallsyms_f, line)) {
+			std::istringstream iss(line);
+			std::string addr, type, func_name;
+			if (!(iss >> addr >> type >> func_name)) {
+				continue;
+			}
+
+			if (!in_init_section) {
+				if (func_name == "__init_begin") {
+					in_init_section = true;
+					continue;
+				}
+			} else if (func_name == "__init_end") {
+				in_init_section = false;
+				continue;
+			}
+
+			if (!in_irq_section) {
+				if (func_name == "__irqentry_text_start") {
+					in_irq_section = true;
+					continue;
+				} else if (func_name == "__irqentry_text_end") {
+					in_irq_section = false;
+					continue;
+				}
+			} else if (func_name == "__irqentry_text_end") {
+				in_irq_section = false;
+				continue;
+			}
+
+			// 过滤掉 NOKPROBE_SYMBOL() 定义的 _kbl_addr_*
+			if (func_name.rfind("_kbl_addr_", 0) == 0) {
+				continue;
+			}
+			// 过滤掉 perf 相关函数
+			if (func_name.rfind("__perf", 0) == 0 || func_name.rfind("perf_", 0) == 0) {
+				continue;
+			}
+			// 过滤掉 __SCT__ 前缀的静态函数
+			if (func_name.rfind("__SCT__", 0) == 0) {
+				continue;
+			}
+			// 过滤掉 GCC 8 编译生成的 .cold 函数
+			if (std::regex_match(func_name, cold_regex)) {
+				continue;
+			}
+
+			if ((type == "t" || type == "T" || type == "w" || type == "W") &&
+			    func_name == event_re &&
+			    blacklist.find(func_name) == blacklist.end() &&
+			    avail_filter.find(func_name) != avail_filter.end()) {
+				fns.insert(func_name);
+			}
+		}
 
-//		printf("111111111\n");
-//		if (name == "events") return _perf_event;
-//
-//		auto a = new PerfEventArrayTable;
-//		a->getMessage();
-//
+		return fns;
 	}
 
-	void php_test(Php::Parameters &params) {
-		int ty = bpf_table_type(this->mod, "counters");
-		Php::out << "counters type]" << ty << std::endl;
-		int ty2 = bpf_table_type(this->mod, "events");
-		Php::out << "events type]" << ty2 << std::endl;
-//		bpf.get_map_in_map_table<int>("").get_fd();
-//		auto aaa = bpf.table<>()("counters");
-//		aaa.get_value(0, reinterpret_cast<std::string &>(val));
-//
-//		auto control_table_hdl = bpf.get_array_table<uint64_t>("counters");
-//		auto res1 = control_table_hdl.get_value(1, val);
-//		Php::out<< "ok]" <<res1.ok() <<std::endl;
-//		Php::out<< "msg]" << res1.msg() <<std::endl;
-//		Php::out <<"val]" << val <<std::endl;
+	Php::Value php_get_kprobe_functions(Php::Parameters &params) {
+		std::string fn = params[0].stringValue();
+		auto res = get_kprobe_functions(fn);
+		Php::Array result;
+		for (const auto &item: res) {
+			result[result.size()] = item; // 将每个匹配的函数名添加到 Php::Array
+		}
+		return result;
+	}
+
+	Php::Value php_test(Php::Parameters &params) {
+		std::string fn = params[0].stringValue();
+		Php::out  << fn << std::endl;
+		auto res = get_kprobe_functions(fn);
+		Php::Array result;
+		for (const auto &item : res) {
+			result[result.size()] = item; // 将每个匹配的函数名添加到 Php::Array
+		}
+		return result;
 	}
 
 	void __construct(Php::Parameters &params) {
@@ -371,13 +473,10 @@ public:
 		}
 	}
 
-	Php::Value php_table(Php::Parameters &params) {
-		std::string table_name = params[0].stringValue();  // Get event_name from the parameters
+	Php::Value php_get_table(Php::Parameters &params) {
+		std::string table_name = params[0].stringValue();
 		int from_fn = 0;
 		return get_table_cls(table_name.c_str(), from_fn);
-
-//		this->_class_perf_event = new PerfEventArrayTable(&this->bpf, table_name);
-//		return Php::Object("PerfEventArrayTable", this->_class_perf_event);
 	}
 
 	void php_perf_buffer_poll(Php::Parameters &params) {
@@ -470,7 +569,7 @@ PHPCPP_EXPORT void *get_module() {
 			Php::ByVal("ev_name", Php::Type::String),
 	});
 
-	ebpf_class.method<&EbpfExtension::php_table>("table", {
+	ebpf_class.method<&EbpfExtension::php_get_table>("get_table", {
 			Php::ByVal("tb_name", Php::Type::String),
 	});
 
@@ -489,31 +588,47 @@ PHPCPP_EXPORT void *get_module() {
 			Php::ByVal("symbol", Php::Type::String),
 			Php::ByVal("options", Php::Type::Array, false),
 	});
-	ebpf_class.method<&EbpfExtension::php_test>("test", {});
+	ebpf_class.method<&EbpfExtension::php_test>("test", {
+			Php::ByVal("idx", Php::Type::String),
+
+	});
+	ebpf_class.method<&EbpfExtension::php_get_kprobe_functions>("get_kprobe_functions", {
+			Php::ByVal("fn", Php::Type::String),
+	});
 	extension.add(std::move(ebpf_class));
 
 	/*HashTable*/
 	Php::Class<HashTable> ebpf_hashtable_cls("HashTable");
+	ebpf_hashtable_cls.method<&HashTable::php_get_values>("values", {
+	});
 	/*ArrayTable*/
 	Php::Class<ArrayTable> ebpf_array_table_cls("ArrayTable");
-	ebpf_array_table_cls.method<&ArrayTable::Value>("value", {
-			Php::ByVal("i", Php::Type::Numeric),
+	ebpf_array_table_cls.method<&ArrayTable::php_get_value>("get_value", {
+			Php::ByVal("idx", Php::Type::Numeric),
 	});
 	/*ProgArrayTable*/
 	Php::Class<ProgArrayTable> ebpf_prog_array_table_cls("ProgArrayTable");
 	/*PerfEventArrayTable*/
 	Php::Class<PerfEventArrayTable> ebpf_perf_event_class("PerfEventArrayTable");
 	ebpf_perf_event_class.method<&PerfEventArrayTable::php_open_perf_buffer>("open_perf_buffer", {
-			Php::ByVal("callback", Php::Type::Callable),
+			Php::ByVal("fn", Php::Type::String),
 	});
 	/*PerCpuHashTable*/
 	Php::Class<PerCpuHashTable> ebpf_percpuhash_table_cls("PerCpuHashTable");
 	/*PerCpuArrayTable*/
-	Php::Class<PerCpuArrayTable> ebpf_percpuarray_table_cls("PerCpuArrayTable");
+	Php::Class<PerCpuArrayTable> ebpf_per_cpu_array_table_cls("PerCpuArrayTable");
+	ebpf_per_cpu_array_table_cls.method<&PerCpuArrayTable::php_sum_value>("sum_value", {
+			Php::ByVal("idx", Php::Type::Numeric),
+	});
 	/*LpmTrieTable*/
 	Php::Class<LpmTrieTable> ebpf_lpmtrie_table_cls("LpmTrieTable");
 	/*StackTraceTable*/
 	Php::Class<StackTraceTable> ebpf_stack_trace_table_cls("StackTraceTable");
+	ebpf_stack_trace_table_cls.method<&StackTraceTable::php_get_values>("values", {
+			Php::ByVal("stack", Php::Type::Numeric),
+			Php::ByVal("pid", Php::Type::Numeric),
+	});
+
 	/*LruHashTable*/
 	Php::Class<LruHashTable> ebpf_lruhash_table_cls("LruHashTable");
 	/*LruPerCpuHashTable*/
@@ -540,7 +655,7 @@ PHPCPP_EXPORT void *get_module() {
 	extension.add(std::move(ebpf_prog_array_table_cls));
 	extension.add(std::move(ebpf_perf_event_class));
 	extension.add(std::move(ebpf_percpuhash_table_cls));
-	extension.add(std::move(ebpf_percpuarray_table_cls));
+	extension.add(std::move(ebpf_per_cpu_array_table_cls));
 	extension.add(std::move(ebpf_lpmtrie_table_cls));
 	extension.add(std::move(ebpf_stack_trace_table_cls));
 	extension.add(std::move(ebpf_lruhash_table_cls));

+ 68 - 158
table.cpp

@@ -1,172 +1,82 @@
-#include <iostream>
-#include <phpcpp.h>
-#include "bpf_module.h"
-#include "BPF.h"
+#include "table.h"
 
-class BaseTable : public Php::Base {
-public:
-	ebpf::BPF *bpf;
-	std::string tb_name;
+//BaseTable::BaseTable(ebpf::BPF *bpf_instance, const std::string &tb_name)
+//: bpf(bpf_instance), tb_name(tb_name){}
 
-	BaseTable(ebpf::BPF *bpf_instance, const std::string &tb_name)
-			: bpf(bpf_instance), tb_name(tb_name) {}
+void BaseTable::printName() {
+	std::cout << "Table name: " << tb_name << std::endl;
+}
 
-	virtual ~BaseTable() = default;
+std::string cb_fn;
 
-	void printName() { std::cout << "Table name: " << tb_name << std::endl; }
-};
+void PerfEventArrayTable::callbackfn(void *cookie, void *data, int data_size) {
+	Php::Value phpData((const char *) data, data_size);
+	Php::call(cb_fn.c_str(), nullptr, phpData, data_size);
+}
 
-
-class PerfEventArrayTable : public BaseTable {
-private:
-	std::string cb;
-public:
-	using BaseTable::BaseTable;
-
-//	ebpf::BPF *bpf;
-//	std::string event_name;
-//
-//	PerfEventArrayTable(ebpf::BPF *bpf_instance, const std::string &event_name)
-//	: bpf(bpf_instance), event_name(event_name) {}
-
-//	using BaseTable::BaseTable;
-
-	virtual ~PerfEventArrayTable() = default;
-
-	static void callbackfn(void *cookie, void *data, int data_size) {
-		auto *instance = static_cast<PerfEventArrayTable *>(cookie);
-		if (!instance) return;
-
-		Php::Value phpData((const char *) data, data_size);
-		Php::call(instance->cb.c_str(), nullptr, phpData, data_size);
+void PerfEventArrayTable::php_open_perf_buffer(Php::Parameters &params) {
+	cb_fn = params[0].stringValue();
+	auto res = this->bpf->open_perf_buffer(this->tb_name, &PerfEventArrayTable::callbackfn);
+	if (!res.ok()) {
+		throw Php::Exception("open_perf_buffer error:" + res.msg());
 	}
-
-	void php_open_perf_buffer(Php::Parameters &params) {
-		this->cb = params[0].stringValue();
-		auto res = this->bpf->open_perf_buffer(this->tb_name, callbackfn, nullptr, this);
-		if (!res.ok()) {
-			throw Php::Exception("open_perf_buffer error:" + res.msg());
-		}
-
-//		auto control_table_hdl = bpf->get_array_table<uint64_t>("counters");
-//		uint64_t val;
-//		auto res1 = control_table_hdl.get_value(0, val);
-//		Php::out << "ok]" << res1.ok() << std::endl;
-//		Php::out << "msg]" << res1.msg() << std::endl;
-//		Php::out << "val]" << val << std::endl;
+}
+
+int PerfEventArrayTable::perf_buffer_poll(int timeout_ms) {
+	return bpf->poll_perf_buffer(this->tb_name, timeout_ms); // perf_reader_event_read
+}
+
+Php::Value ArrayTable::php_get_value(Php::Parameters &param) {
+	auto index = param[0].numericValue();
+	// todo val type
+	uint64_t val;
+	auto table = bpf->get_array_table<uint64_t>(tb_name);
+	auto res = table.get_value(index, val);
+	if (!res.ok()) {
+		throw Php::Exception("Get value error in" + std::string(tb_name));
 	}
-
-	int perf_buffer_poll(int timeout_ms) {
-		return bpf->poll_perf_buffer(this->tb_name, timeout_ms); // perf_reader_event_read
+	Php::Value phpValue = static_cast<int64_t>(val);
+	return phpValue;
+}
+
+Php::Value StackTraceTable::php_get_values(Php::Parameters &param) {
+	auto stack_id = param[0].numericValue();
+	auto pid = param[1].numericValue();
+	auto table = bpf->get_stack_table(tb_name);
+
+	auto symbols = table.get_stack_symbol((int) stack_id, (int) pid);
+	std::vector<std::string> result;
+	for (const auto &str: symbols) {
+		result.push_back(Php::Value(str));
 	}
-
-};
-
-class HashTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class ArrayTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-	Php::Value Value(Php::Parameters &param) {
-		auto index = param[0].numericValue();
-		// todo val type
-		uint64_t val;
-		auto table = bpf->get_array_table<uint64_t>(tb_name);
-		auto res = table.get_value(index, val);
-		if (!res.ok()) {
-			throw Php::Exception("Get value error in" + std::string(tb_name));
-		}
-		Php::Value phpValue = static_cast<int64_t>(val);
-		return phpValue;
+	return Php::Array(result);
+}
+
+Php::Value HashTable::php_get_values() {
+	Php::Array result;
+	auto table = bpf->get_hash_table<uint64_t, uint64_t>(tb_name);
+	auto entries = table.get_table_offline();
+	for (const auto &[key, value]: entries) {
+		result[key] = Php::Value(static_cast<int64_t>(value));
 	}
-};
-
-class ProgArrayTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
 
-	void Value(Php::Parameters &param) {
-		auto index = param[0].numericValue();
-		// todo key type
-		uint64_t val;
-		auto table = bpf->get_array_table<uint64_t>(tb_name);
-		auto res = table.get_value(index, val);
+	return result;
+}
 
-		printf("%d\n", val);
+Php::Value PerCpuArrayTable::php_sum_value(Php::Parameters &param) {
+	auto index = param[0].numericValue();
+	std::vector<unsigned long> val;
+	auto table = bpf->get_percpu_array_table<uint64_t>(tb_name);
+	auto res = table.get_value(index, val);
+	if (!res.ok()) {
+		throw Php::Exception("Get value error in" + std::string(tb_name));
 	}
+	unsigned long long sum = 0;
+	for (const auto &v: val) {
+		sum += v;
+	}
+	Php::Value phpValue = static_cast<int64_t>(sum);
+	return phpValue;
+}
 
 
-};
-
-class PerCpuHashTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class PerCpuArrayTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class LpmTrieTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class StackTraceTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class LruHashTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class LruPerCpuHashTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class CgroupArrayTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class DevMapTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class CpuMapTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class XskMapTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class MapInMapArrayTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class MapInMapHashTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class QueueStackTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};
-
-class RingBufTable : public BaseTable {
-public:
-	using BaseTable::BaseTable;
-};

+ 147 - 0
table.h

@@ -0,0 +1,147 @@
+#ifndef PHPCPP_HELLOWORLD_TABLE_H
+#define PHPCPP_HELLOWORLD_TABLE_H
+#include <iostream>
+#include <phpcpp.h>
+#include "bpf_module.h"
+#include "BPF.h"
+
+
+class BaseTable : public Php::Base {
+public:
+	ebpf::BPF *bpf;
+	std::string tb_name;
+
+	BaseTable(ebpf::BPF *bpf_instance, const std::string &tb_name)
+			: bpf(bpf_instance), tb_name(tb_name) {}
+
+	virtual ~BaseTable() = default;
+
+	void printName();
+
+//	void printName() { std::cout << "Table name: " << tb_name << std::endl; }
+
+//	Php::Value Value(Php::Parameters &param) {
+//		auto index = param[0].numericValue();
+//		// todo val type
+//		uint64_t val;
+//		auto table = bpf->get_array_table<uint64_t>(tb_name);
+//		auto res = table.get_value(index, val);
+//		if (!res.ok()) {
+//			throw Php::Exception("Get value error in" + std::string(tb_name));
+//		}
+//		Php::Value phpValue = static_cast<int64_t>(val);
+//		return phpValue;
+//	}
+
+};
+
+
+class PerfEventArrayTable : public BaseTable {
+private:
+	std::string cb;
+public:
+	using BaseTable::BaseTable;
+	virtual ~PerfEventArrayTable() = default;
+	static void callbackfn(void *cookie, void *data, int data_size);
+	void php_open_perf_buffer(Php::Parameters &params);
+	int perf_buffer_poll(int timeout_ms);
+};
+
+class HashTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+	Php::Value php_get_values();
+};
+
+class ArrayTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+	Php::Value php_get_value(Php::Parameters &param);
+};
+
+class ProgArrayTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+
+//	void Value(Php::Parameters &param) {
+//		auto index = param[0].numericValue();
+//		// todo key type
+//		uint64_t val;
+//		auto table = bpf->get_array_table<uint64_t>(tb_name);
+////		virtual StatusTuple get_value(const int& index, ValueType& value) {
+//		auto res = table.get_value(index, val);
+//	}
+};
+
+class PerCpuHashTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class PerCpuArrayTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+	Php::Value php_sum_value(Php::Parameters &param);
+};
+
+class LpmTrieTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class StackTraceTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+	Php::Value php_get_values(Php::Parameters &param);
+};
+
+class LruHashTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class LruPerCpuHashTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class CgroupArrayTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class DevMapTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class CpuMapTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class XskMapTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class MapInMapArrayTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class MapInMapHashTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class QueueStackTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+
+class RingBufTable : public BaseTable {
+public:
+	using BaseTable::BaseTable;
+};
+#endif //PHPCPP_HELLOWORLD_TABLE_H