| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 7 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2018 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | [email protected] so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: |
- +----------------------------------------------------------------------+
- */
- /* $Id$ */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- extern "C" {
- #include "php.h"
- #include "php_ini.h"
- #include "ext/standard/info.h"
- }
- #include "BPF.h"
- #include "php_ebpf.h"
- #include "bcc_common.h"
- #include <string>
- #include <fstream>
- #include <sstream>
- #include <regex>
- /* Handlers */
- zend_object_handlers bpf_object_handlers;
- zend_object_handlers table_object_handlers;
- /* Class entries */
- zend_class_entry *bpf_ce;
- zend_class_entry *perf_event_array_table_ce;
- zend_class_entry *hash_table_ce;
- zend_class_entry *array_table_ce;
- zend_class_entry *prog_array_table_ce;
- zend_class_entry *per_cpu_hash_table_ce;
- zend_class_entry *per_cpu_array_table_ce;
- zend_class_entry *lpm_trie_table_ce;
- zend_class_entry *stack_trace_table_ce;
- zend_class_entry *lru_hash_table_ce;
- zend_class_entry *lru_per_cpu_hash_table_ce;
- zend_class_entry *cgroup_array_table_ce;
- zend_class_entry *dev_map_table_ce;
- zend_class_entry *cpu_map_table_ce;
- zend_class_entry *xsk_map_table_ce;
- zend_class_entry *map_in_map_array_table_ce;
- zend_class_entry *map_in_map_hash_table_ce;
- zend_class_entry *queue_stack_table_ce;
- zend_class_entry *ring_buf_table_ce;
- zend_class_entry *bpf_prog_func_ce;
- /* Objects */
- typedef struct _bpf_object {
- EbpfExtension *ebpf_cpp_cls;
- zend_object std;
- } bpf_object;
- typedef struct _sub_object {
- ebpf::BPF *bpf;
- zend_object std;
- } sub_object;
- std::string cb_fn;
- void callbackfn(void *cookie, void *data, int data_size) {
- zval params[3];
- zval retval;
- ZVAL_LONG(¶ms[0], 0);
- ZVAL_STRINGL(¶ms[1], (const char *) data, data_size);
- ZVAL_LONG(¶ms[2], data_size);
- zval function_name;
- ZVAL_STRING(&function_name, cb_fn.c_str());
- if (call_user_function(EG(function_table), nullptr, &function_name, &retval, 3, params) == SUCCESS) {
- zval_ptr_dtor(&retval);
- } else {
- php_error_docref(NULL, E_WARNING, "Failed to call callback function '%s'", cb_fn.c_str());
- }
- zval_ptr_dtor(¶ms[0]);
- zval_ptr_dtor(¶ms[1]);
- zval_ptr_dtor(¶ms[2]);
- zval_ptr_dtor(&function_name);
- }
- static inline bpf_object *bpf_fetch_object(zend_object *obj) {
- return (bpf_object *) ((char *) (obj) - XtOffsetOf(bpf_object, std));
- }
- static inline sub_object *table_fetch_object(zend_object *obj) {
- return (sub_object *) ((char *) (obj) - XtOffsetOf(sub_object, std));
- }
- void EbpfExtension::_trace_autoload() {
- size_t num_funcs = bpf.get_num_functions();
- for (size_t i = 0; i < num_funcs; i++) {
- const char *func_name = bpf.get_function_name(i);
- std::string fn_name(func_name);
- if (fn_name.rfind("kprobe__", 0) == 0) {
- std::string kernel_func = fix_syscall_fnname(fn_name.substr(8));
- bpf.attach_kprobe(kernel_func, fn_name);
- } else if (fn_name.rfind("kretprobe__", 0) == 0) {
- std::string kernel_func = fix_syscall_fnname(fn_name.substr(11));
- bpf.attach_kprobe(kernel_func, fn_name, 0, BPF_PROBE_RETURN);
- } else if (fn_name.rfind("tracepoint__", 0) == 0) {
- std::string tp_name = fn_name.substr(12);
- size_t sep = tp_name.find("__");
- if (sep != std::string::npos) {
- tp_name.replace(sep, 2, ":");
- }
- bpf.attach_tracepoint(tp_name, fn_name);
- } else if (fn_name.rfind("raw_tracepoint__", 0) == 0) {
- std::string tp_name = fn_name.substr(16);
- bpf.attach_raw_tracepoint(tp_name, fn_name);
- } else if (fn_name.rfind("kfunc__", 0) == 0) {
- fn_name = add_prefix("kfunc__", fn_name);
- attach_kfunc(fn_name);
- } else if (fn_name.rfind("kretfunc__", 0) == 0) {
- fn_name = add_prefix("kretfunc__", fn_name);
- this->attach_kfunc(fn_name);
- } else if (fn_name.rfind("lsm__", 0) == 0) {
- fn_name = add_prefix("lsm__", fn_name);
- this->attach_lsm(fn_name);
- }
- }
- }
- std::string EbpfExtension::add_prefix(const std::string &prefix, const std::string &name) {
- if (name.rfind(prefix, 0) != 0) {
- return prefix + name;
- }
- return name;
- }
- std::string EbpfExtension::fix_syscall_fnname(const std::string &name) {
- for (const auto &prefix: syscall_prefixes) {
- if (name.rfind(prefix, 0) == 0) {
- return bpf.get_syscall_fnname(name.substr(prefix.length()));
- }
- }
- return name;
- }
- zval EbpfExtension::get_table_cls(const char *table_name, int from_attr) {
- zval retval;
- ZVAL_NULL(&retval);
- int ttype = bpf_table_type(this->mod, table_name);
- switch (ttype) {
- case BPF_MAP_TYPE_HASH: {
- if (!hash_table_ce) {
- zend_throw_error(NULL, "HashTable class not found");
- return retval;
- }
- object_init_ex(&retval, hash_table_ce);
- zend_update_property_string(hash_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_ARRAY: {
- if (!array_table_ce) {
- zend_throw_error(NULL, "ArrayTable class not found");
- return retval;
- }
- object_init_ex(&retval, array_table_ce);
- zend_update_property_string(array_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_PROG_ARRAY: {
- if (!prog_array_table_ce) {
- zend_throw_error(NULL, "ProgArrayTable class not found");
- return retval;
- }
- object_init_ex(&retval, prog_array_table_ce);
- zend_update_property_string(prog_array_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_PERF_EVENT_ARRAY: {
- if (Z_TYPE(_class_perf_event_obj) != IS_UNDEF) {
- ZVAL_COPY(&retval, &_class_perf_event_obj);
- return retval;
- }
- if (!perf_event_array_table_ce) {
- zend_throw_error(NULL, "PerfEventArrayTable class not found");
- return retval;
- }
- object_init_ex(&retval, perf_event_array_table_ce);
- zend_update_property_string(perf_event_array_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- ZVAL_COPY(&_class_perf_event_obj, &retval);
- return retval;
- }
- case BPF_MAP_TYPE_PERCPU_HASH: {
- if (!per_cpu_hash_table_ce) {
- zend_throw_error(NULL, "PerCpuHashTable class not found");
- return retval;
- }
- object_init_ex(&retval, per_cpu_hash_table_ce);
- zend_update_property_string(per_cpu_hash_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_PERCPU_ARRAY: {
- if (!per_cpu_array_table_ce) {
- zend_throw_error(NULL, "PerCpuArrayTable class not found");
- return retval;
- }
- object_init_ex(&retval, per_cpu_array_table_ce);
- zend_update_property_string(per_cpu_array_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_LPM_TRIE: {
- if (!lpm_trie_table_ce) {
- zend_throw_error(NULL, "LpmTrieTable class not found");
- return retval;
- }
- object_init_ex(&retval, lpm_trie_table_ce);
- zend_update_property_string(lpm_trie_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_STACK_TRACE: {
- if (!stack_trace_table_ce) {
- zend_throw_error(NULL, "StackTraceTable class not found");
- return retval;
- }
- object_init_ex(&retval, stack_trace_table_ce);
- zend_update_property_string(stack_trace_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_LRU_HASH: {
- if (!lru_hash_table_ce) {
- zend_throw_error(NULL, "LruHashTable class not found");
- return retval;
- }
- object_init_ex(&retval, lru_hash_table_ce);
- zend_update_property_string(lru_hash_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_LRU_PERCPU_HASH: {
- if (!lru_per_cpu_hash_table_ce) {
- zend_throw_error(NULL, "LruPerCpuHashTable class not found");
- return retval;
- }
- object_init_ex(&retval, lru_per_cpu_hash_table_ce);
- zend_update_property_string(lru_per_cpu_hash_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_CGROUP_ARRAY: {
- if (!cgroup_array_table_ce) {
- zend_throw_error(NULL, "CgroupArrayTable class not found");
- return retval;
- }
- object_init_ex(&retval, cgroup_array_table_ce);
- zend_update_property_string(cgroup_array_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_DEVMAP: {
- if (!dev_map_table_ce) {
- zend_throw_error(NULL, "DevMapTable class not found");
- return retval;
- }
- object_init_ex(&retval, dev_map_table_ce);
- zend_update_property_string(dev_map_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_CPUMAP: {
- if (!cpu_map_table_ce) {
- zend_throw_error(NULL, "CpuMapTable class not found");
- return retval;
- }
- object_init_ex(&retval, cpu_map_table_ce);
- zend_update_property_string(cpu_map_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_XSKMAP: {
- if (!xsk_map_table_ce) {
- zend_throw_error(NULL, "XskMapTable class not found");
- return retval;
- }
- object_init_ex(&retval, xsk_map_table_ce);
- zend_update_property_string(xsk_map_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_ARRAY_OF_MAPS: {
- if (!map_in_map_array_table_ce) {
- zend_throw_error(NULL, "MapInMapArrayTable class not found");
- return retval;
- }
- object_init_ex(&retval, map_in_map_array_table_ce);
- zend_update_property_string(map_in_map_array_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_HASH_OF_MAPS: {
- if (!map_in_map_hash_table_ce) {
- zend_throw_error(NULL, "MapInMapHashTable class not found");
- return retval;
- }
- object_init_ex(&retval, map_in_map_hash_table_ce);
- zend_update_property_string(map_in_map_hash_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_QUEUE:
- case BPF_MAP_TYPE_STACK: {
- if (!queue_stack_table_ce) {
- zend_throw_error(NULL, "QueueStackTable class not found");
- return retval;
- }
- object_init_ex(&retval, queue_stack_table_ce);
- zend_update_property_string(queue_stack_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- case BPF_MAP_TYPE_RINGBUF: {
- if (!ring_buf_table_ce) {
- zend_throw_error(NULL, "RingBufTable class not found");
- return retval;
- }
- object_init_ex(&retval, ring_buf_table_ce);
- zend_update_property_string(ring_buf_table_ce, &retval, "name", sizeof("name") - 1, table_name);
- sub_object *table_obj = table_fetch_object(Z_OBJ(retval));
- table_obj->bpf = &this->bpf;
- Z_ADDREF(retval);
- break;
- }
- default:
- if (from_attr) {
- ZVAL_LONG(&retval, ttype);
- }
- zend_throw_error(NULL, "Unknown table type %d", ttype);
- return retval;
- }
- return retval;
- }
- std::unordered_set<std::string> EbpfExtension::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;
- }
- if (func_name.rfind("_kbl_addr_", 0) == 0) {
- continue;
- }
- if (func_name.rfind("__perf", 0) == 0 || func_name.rfind("perf_", 0) == 0) {
- continue;
- }
- if (func_name.rfind("__SCT__", 0) == 0) {
- continue;
- }
- 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);
- }
- }
- return fns;
- }
- ebpf::StatusTuple EbpfExtension::attach_kfunc(const std::string &kfn) {
- int probe_fd;
- auto fn = bpf.load_func(kfn, BPF_PROG_TYPE_TRACING, probe_fd);
- int res_fd = bpf_attach_kfunc(probe_fd);
- if (res_fd < 0) {
- TRY2(bpf.unload_func(kfn));
- return ebpf::StatusTuple(-1, "Unable to attach kfunc using %s",
- kfn.c_str());
- }
- return ebpf::StatusTuple::OK();
- }
- ebpf::StatusTuple EbpfExtension::attach_lsm(const std::string &lsm) {
- int probe_fd;
- auto fn = bpf.load_func(lsm, BPF_PROG_TYPE_LSM, probe_fd);
- int res_fd = bpf_attach_lsm(probe_fd);
- if (res_fd < 0) {
- TRY2(bpf.unload_func(lsm));
- return ebpf::StatusTuple(-1, "Unable to attach lsm using %s",
- lsm.c_str());
- }
- return ebpf::StatusTuple::OK();
- }
- zend_object *bpf_create_object(zend_class_entry *ce) {
- bpf_object *intern = (bpf_object *) ecalloc(1, sizeof(bpf_object) + zend_object_properties_size(ce));
- intern->ebpf_cpp_cls = new EbpfExtension();
- zend_object_std_init(&intern->std, ce);
- object_properties_init(&intern->std, ce);
- intern->std.handlers = &bpf_object_handlers;
- return &intern->std;
- }
- void bpf_free_object(zend_object *object) {
- bpf_object *intern = bpf_fetch_object(object);
- zend_object_std_dtor(&intern->std);
- }
- zend_object *table_create_object(zend_class_entry *ce TSRMLS_DC) {
- sub_object *intern = (sub_object *) ecalloc(1, sizeof(sub_object) + zend_object_properties_size(ce));
- zend_object_std_init(&intern->std, ce);
- object_properties_init(&intern->std, ce);
- intern->std.handlers = &table_object_handlers;
- return &intern->std;
- }
- void table_free_object(zend_object *object) {
- sub_object *intern = table_fetch_object(object);
- zend_object_std_dtor(&intern->std);
- }
- /* {{{ PHP_INI
- */
- /* Remove comments and fill if you need to have entries in php.ini
- PHP_INI_BEGIN()
- STD_PHP_INI_ENTRY("ebpf.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_ebpf_globals, ebpf_globals)
- STD_PHP_INI_ENTRY("ebpf.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_ebpf_globals, ebpf_globals)
- PHP_INI_END()
- */
- /* }}} */
- /* Remove the following function when you have successfully modified config.m4
- so that your module can be compiled into PHP, it exists only for testing
- purposes. */
- /* Every user-visible function in PHP should document itself in the source */
- /* {{{ proto string confirm_ebpf_compiled(string arg)
- Return a string to confirm that the module is compiled in */
- PHP_METHOD (Bpf, __construct) {
- zval *opts;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &opts) == FAILURE) {
- zend_throw_error(NULL, "Expected options array");
- return;
- }
- if (Z_OBJCE_P(getThis()) != bpf_ce) {
- zend_throw_error(NULL, "Invalid object type");
- return;
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- zval *text = zend_hash_str_find(Z_ARRVAL_P(opts), "text", strlen("text"));
- if (text && Z_TYPE_P(text) == IS_STRING) {
- std::string source(Z_STRVAL_P(text), Z_STRLEN_P(text));
- if (!obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid internal C++ object");
- RETURN_NULL();
- }
- auto res = obj->ebpf_cpp_cls->init(source);
- if (!res.ok()) {
- zend_throw_error(NULL, "BPF init failed: %s", res.msg().c_str());
- RETURN_FALSE;
- }
- obj->ebpf_cpp_cls->_trace_autoload();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, __get) {
- char *name;
- size_t name_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- int from_attr = 1;
- zval table = obj->ebpf_cpp_cls->get_table_cls(name, from_attr);
- RETURN_ZVAL(&table, 1, 0);
- }
- PHP_METHOD (Bpf, get_kprobe_functions) {
- char *fn;
- size_t fn_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &fn, &fn_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto res = obj->ebpf_cpp_cls->get_kprobe_functions(std::string(fn, fn_len));
- array_init(return_value);
- for (const auto &item: res) {
- add_next_index_string(return_value, item.c_str());
- }
- }
- PHP_METHOD (Bpf, attach_kprobe) {
- char *kernel_func, *probe_func;
- size_t kernel_func_len, probe_func_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &kernel_func, &kernel_func_len,
- &probe_func, &probe_func_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto attach_res = obj->ebpf_cpp_cls->bpf.attach_kprobe(
- std::string(kernel_func, kernel_func_len),
- std::string(probe_func, probe_func_len)
- );
- if (!attach_res.ok()) {
- zend_throw_error(NULL, "attach error: %s", attach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, attach_tracepoint) {
- char *tp_func, *probe_func;
- size_t tp_func_len, probe_func_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &tp_func, &tp_func_len,
- &probe_func, &probe_func_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto attach_res = obj->ebpf_cpp_cls->bpf.attach_tracepoint(
- std::string(tp_func, tp_func_len),
- std::string(probe_func, probe_func_len)
- );
- if (!attach_res.ok()) {
- zend_throw_error(NULL, "attach error: %s", attach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, attach_raw_tracepoint) {
- char *tp_func, *probe_func;
- size_t tp_func_len, probe_func_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &tp_func, &tp_func_len,
- &probe_func, &probe_func_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto attach_res = obj->ebpf_cpp_cls->bpf.attach_raw_tracepoint(
- std::string(tp_func, tp_func_len),
- std::string(probe_func, probe_func_len)
- );
- if (!attach_res.ok()) {
- zend_throw_error(NULL, "attach error: %s", attach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, attach_kfunc) {
- char *kfunc;
- size_t kfunc_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &kfunc, &kfunc_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto attach_res = obj->ebpf_cpp_cls->attach_kfunc(std::string(kfunc, kfunc_len));
- if (!attach_res.ok()) {
- zend_throw_error(NULL, "attach error: %s", attach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, attach_lsm) {
- char *lsm;
- size_t lsm_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &lsm, &lsm_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto attach_res = obj->ebpf_cpp_cls->attach_lsm(std::string(lsm, lsm_len));
- if (!attach_res.ok()) {
- zend_throw_error(NULL, "attach error: %s", attach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, attach_uprobe) {
- char *binary_path, *symbol, *probe_func;
- size_t binary_path_len, symbol_len, probe_func_len;
- zval *options = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|a",
- &binary_path, &binary_path_len,
- &symbol, &symbol_len,
- &probe_func, &probe_func_len,
- &options) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- int64_t symbol_addr = 0, symbol_offset = 0, pid_param = 0;
- uint32_t ref_ctr_offset = 0;
- pid_t pid = -1;
- if (options && Z_TYPE_P(options) == IS_ARRAY) {
- zval *tmp;
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "symbol_addr", strlen("symbol_addr"))) != NULL) {
- symbol_addr = zval_get_long(tmp);
- }
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "symbol_offset", strlen("symbol_offset"))) != NULL) {
- symbol_offset = zval_get_long(tmp);
- }
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "ref_ctr_offset", strlen("ref_ctr_offset"))) != NULL) {
- ref_ctr_offset = (uint32_t) zval_get_long(tmp);
- }
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "pid", strlen("pid"))) != NULL) {
- pid_param = zval_get_long(tmp);
- if (pid_param > 0) {
- pid = static_cast<pid_t>(pid_param);
- }
- }
- }
- auto attach_res = obj->ebpf_cpp_cls->bpf.attach_uprobe(
- std::string(binary_path, binary_path_len),
- std::string(symbol, symbol_len),
- std::string(probe_func, probe_func_len),
- symbol_addr,
- BPF_PROBE_ENTRY,
- pid,
- symbol_offset,
- ref_ctr_offset
- );
- if (!attach_res.ok()) {
- zend_throw_error(NULL, "attach_uprobe error: %s", attach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, detach_kprobe) {
- char *fn;
- size_t fn_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &fn, &fn_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto detach_res = obj->ebpf_cpp_cls->bpf.detach_kprobe(std::string(fn, fn_len));
- if (!detach_res.ok()) {
- zend_throw_error(NULL, "detach_kprobe error: %s", detach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, detach_uprobe) {
- char *binary_path, *symbol;
- size_t binary_path_len, symbol_len;
- zval *options = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|a",
- &binary_path, &binary_path_len,
- &symbol, &symbol_len,
- &options) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- int64_t symbol_addr = 0, symbol_offset = 0, pid_param = 0;
- pid_t pid = -1;
- if (options && Z_TYPE_P(options) == IS_ARRAY) {
- zval *tmp;
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "symbol_addr", strlen("symbol_addr"))) != NULL) {
- symbol_addr = zval_get_long(tmp);
- }
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "symbol_offset", strlen("symbol_offset"))) != NULL) {
- symbol_offset = zval_get_long(tmp);
- }
- if ((tmp = zend_hash_str_find(Z_ARRVAL_P(options), "pid", strlen("pid"))) != NULL) {
- pid_param = zval_get_long(tmp);
- if (pid_param > 0) {
- pid = static_cast<pid_t>(pid_param);
- }
- }
- }
- auto detach_res = obj->ebpf_cpp_cls->bpf.detach_uprobe(
- std::string(binary_path, binary_path_len),
- std::string(symbol, symbol_len),
- symbol_addr,
- BPF_PROBE_ENTRY,
- pid,
- symbol_offset
- );
- if (!detach_res.ok()) {
- zend_throw_error(NULL, "detach_uprobe error: %s", detach_res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (Bpf, trace_print) {
- char *fmt = NULL;
- size_t fmt_len = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &fmt, &fmt_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- std::ifstream pipe(TRACE_PIPE_PATH);
- if (!pipe.is_open()) {
- zend_throw_error(NULL, "Failed to open trace_pipe");
- RETURN_NULL();
- }
- std::string line;
- while (true) {
- if (!std::getline(pipe, line)) {
- continue;
- }
- if (line.empty() || line.rfind("CPU:", 0) == 0) {
- continue;
- }
- std::string task = line.substr(0, 16);
- task.erase(0, task.find_first_not_of(" "));
- std::istringstream iss(line.substr(17));
- std::string pid, cpu, flags, ts, msg;
- char delim;
- if (!(iss >> pid >> delim >> cpu >> delim >> flags >> ts)) {
- continue;
- }
- size_t sym_end = iss.str().find(": ", iss.tellg());
- if (sym_end != std::string::npos) {
- msg = iss.str().substr(sym_end + 2);
- }
- std::vector<std::string> fields = {task, pid, cpu, flags, ts, msg};
- if (fmt == NULL) {
- php_printf("%s\n", line.c_str());
- } else {
- std::string output(fmt, fmt_len);
- std::regex pattern(R"(\{(\d+)\})");
- std::smatch match;
- while (std::regex_search(output, match, pattern)) {
- int index = std::stoi(match[1]);
- std::string replacement = (index >= 0 && index < (int) fields.size()) ? fields[index] : "";
- output.replace(match.position(0), match.length(0), replacement);
- }
- php_printf("%s\n", output.c_str());
- }
- }
- }
- PHP_METHOD (Bpf, trace_fields) {
- std::ifstream traceFile(TRACE_PIPE_PATH);
- if (!traceFile.is_open()) {
- zend_throw_error(NULL, "Failed to open trace_pipe");
- RETURN_NULL();
- }
- std::string line;
- while (std::getline(traceFile, line)) {
- if (line.empty() || line.rfind("CPU:", 0) == 0) {
- continue;
- }
- std::string task = line.substr(0, 16);
- task.erase(0, task.find_first_not_of(' '));
- std::istringstream iss(line.substr(17));
- std::string pid, cpu, flags, ts, msg;
- char delim;
- if (!(iss >> pid >> delim >> cpu >> delim >> flags >> ts)) {
- continue;
- }
- size_t sym_end = iss.str().find(": ", iss.tellg());
- if (sym_end != std::string::npos) {
- msg = iss.str().substr(sym_end + 2);
- }
- array_init(return_value);
- add_index_string(return_value, 0, task.c_str());
- add_index_long(return_value, 1, std::stoi(pid));
- add_index_long(return_value, 2, std::stoi(cpu.substr(1, cpu.size() - 2)));
- add_index_string(return_value, 3, flags.c_str());
- add_index_double(return_value, 4, std::stod(ts));
- add_index_stringl(return_value, 5, msg.c_str(), msg.size());
- return;
- }
- RETURN_NULL();
- }
- PHP_METHOD (Bpf, get_table) {
- char *table_name;
- size_t table_name_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &table_name, &table_name_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- int from_fn = 0;
- auto table = obj->ebpf_cpp_cls->get_table_cls(table_name, from_fn);
- if (Z_TYPE(table) == IS_NULL) {
- RETURN_NULL();
- }
- RETURN_ZVAL(&table, 1, 0);
- }
- PHP_METHOD (Bpf, perf_buffer_poll) {
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- zval name_rv;
- zval *name_zv = zend_read_property(
- perf_event_array_table_ce,
- &obj->ebpf_cpp_cls->_class_perf_event_obj,
- "name", strlen("name"),
- 1,
- &name_rv
- );
- if (!name_zv || Z_TYPE_P(name_zv) != IS_STRING) {
- zend_throw_error(NULL, "Invalid or missing name property");
- RETURN_NULL();
- }
- int timeout_ms = -1;
- int res = obj->ebpf_cpp_cls->bpf.poll_perf_buffer(std::string(Z_STRVAL_P(name_zv), Z_STRLEN_P(name_zv)),
- timeout_ms);
- if (res < 0) {
- zend_throw_error(NULL, "perf buffer poll error.");
- }
- }
- PHP_METHOD (Bpf, get_syscall_fnname) {
- char *name;
- size_t name_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- std::string result = obj->ebpf_cpp_cls->bpf.get_syscall_fnname(std::string(name, name_len));
- RETURN_STRING(result.c_str());
- }
- PHP_METHOD (Bpf, load_func) {
- char *fn;
- size_t fn_len;
- zend_long prog_type;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &fn, &fn_len, &prog_type) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- int probe_fd;
- auto res = obj->ebpf_cpp_cls->bpf.load_func(
- std::string(fn, fn_len),
- static_cast<bpf_prog_type>(prog_type),
- probe_fd
- );
- if (!res.ok()) {
- zend_throw_error(NULL, "Failed to load function: %s", res.msg().c_str());
- RETURN_NULL();
- }
- object_init_ex(return_value, bpf_prog_func_ce);
- zval name_zv;
- ZVAL_STRINGL(&name_zv, fn, fn_len);
- zend_update_property(bpf_prog_func_ce, return_value, "name", sizeof("name") - 1, &name_zv);
- zval_ptr_dtor(&name_zv);
- zval fd_zv;
- ZVAL_LONG(&fd_zv, probe_fd);
- zend_update_property(bpf_prog_func_ce, return_value, "fd", sizeof("fd") - 1, &fd_zv);
- }
- PHP_METHOD (Bpf, attach_raw_socket) {
- zval *prog_fn;
- char *interface;
- size_t interface_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "os", &prog_fn, &interface, &interface_len) == FAILURE) {
- RETURN_NULL();
- }
- bpf_object *obj = bpf_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->ebpf_cpp_cls) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- if (Z_TYPE_P(prog_fn) != IS_OBJECT) {
- zend_throw_error(NULL, "First parameter must be a BPFProgFunction object");
- RETURN_NULL();
- }
- zval rv;
- zval *fd = zend_read_property(Z_OBJCE_P(prog_fn), prog_fn, "fd", strlen("fd"), 1, &rv);
- if (!fd || Z_TYPE_P(fd) != IS_LONG) {
- zend_throw_error(NULL, "Invalid BPFProgFunction object: missing or invalid fd property");
- RETURN_NULL();
- }
- int sock = bpf_open_raw_sock(interface);
- if (sock < 0) {
- zend_throw_error(NULL, "Failed to open raw socket on interface: %s", interface);
- RETURN_NULL();
- }
- int res = bpf_attach_socket(sock, Z_LVAL_P(fd));
- if (res < 0) {
- close(sock);
- zend_throw_error(NULL, "Failed to attach BPF program to socket");
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (PerfEventArrayTable, open_perf_buffer) {
- char *cb_fn_str = NULL;
- size_t cb_fn_len = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &cb_fn_str, &cb_fn_len) == FAILURE) {
- RETURN_NULL();
- }
- zval name_rv;
- zval *name_zv = zend_read_property(
- Z_OBJCE_P(getThis()),
- getThis(),
- "name",
- sizeof("name") - 1,
- 1,
- &name_rv
- );
- if (!name_zv || Z_TYPE_P(name_zv) != IS_STRING) {
- zend_throw_error(NULL, "Invalid or missing name property");
- RETURN_NULL();
- }
- const char *name = Z_STRVAL_P(name_zv);
- cb_fn = std::string(cb_fn_str, cb_fn_len);
- sub_object *obj = table_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->bpf) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto res = obj->bpf->open_perf_buffer(name, callbackfn);
- if (!res.ok()) {
- zend_throw_error(NULL, "open_perf_buffer error: %s", res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (HashTable, values) {
- zval name_rv;
- zval *name_zv;
- name_zv = zend_read_property(
- Z_OBJCE_P(getThis()),
- getThis(),
- "name",
- sizeof("name") - 1,
- 1,
- &name_rv
- );
- if (!name_zv || Z_TYPE_P(name_zv) != IS_STRING) {
- zend_throw_error(NULL, "Invalid or missing name property");
- RETURN_NULL();
- }
- sub_object *obj = table_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->bpf) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- std::vector<std::pair<std::vector<char>, std::vector<char>>> entries;
- auto table = obj->bpf->get_table(Z_STRVAL_P(name_zv));
- auto status = table.get_table_offline_ptr(entries);
- if (status.code() != 0) {
- zend_throw_error(NULL, "Failed to get table values: %s", status.msg().c_str());
- RETURN_NULL();
- }
- array_init(return_value);
- for (const auto &pair: entries) {
- const auto &key_data = pair.first;
- const auto &val_data = pair.second;
- zval entry;
- array_init(&entry);
- add_assoc_stringl(&entry, "key", key_data.data(), key_data.size());
- add_assoc_stringl(&entry, "value", val_data.data(), val_data.size());
- add_next_index_zval(return_value, &entry);
- }
- }
- PHP_METHOD (HashTable, clear) {
- zval name_rv;
- zval *name_zv;
- name_zv = zend_read_property(
- Z_OBJCE_P(getThis()),
- getThis(),
- "name",
- sizeof("name") - 1,
- 1,
- &name_rv
- );
- if (!name_zv || Z_TYPE_P(name_zv) != IS_STRING) {
- zend_throw_error(NULL, "Invalid or missing name property");
- RETURN_NULL();
- }
- sub_object *obj = table_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->bpf) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto table = obj->bpf->get_table(Z_STRVAL_P(name_zv));
- auto res = table.clear_table_non_atomic();
- if (!res.ok()) {
- zend_throw_error(NULL, "Failed to clear table: %s", res.msg().c_str());
- RETURN_NULL();
- }
- RETURN_TRUE;
- }
- PHP_METHOD (ArrayTable, get_value) {
- return;
- }
- PHP_METHOD (ArrayTable, print_log2_hist) {
- return;
- }
- PHP_METHOD (ArrayTable, print_linear_hist) {
- return;
- }
- PHP_METHOD (PerCpuArrayTable, sum_value) {
- int64_t index;
- zval name_rv;
- zval *name_zv;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
- RETURN_NULL();
- }
- name_zv = zend_read_property(
- Z_OBJCE_P(getThis()),
- getThis(),
- "name",
- sizeof("name") - 1,
- 1,
- &name_rv
- );
- if (!name_zv || Z_TYPE_P(name_zv) != IS_STRING) {
- zend_throw_error(NULL, "Invalid or missing name property");
- RETURN_NULL();
- }
- sub_object *obj = table_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->bpf) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- std::vector<unsigned long> val;
- try {
- auto table = obj->bpf->get_percpu_array_table<uint64_t>(Z_STRVAL_P(name_zv));
- auto res = table.get_value(index, val);
- if (!res.ok()) {
- zend_throw_error(NULL, "Get value error in %s", Z_STRVAL_P(name_zv));
- RETURN_NULL();
- }
- unsigned long long sum = 0;
- for (const auto &v: val) {
- sum += v;
- }
- RETURN_LONG(sum);
- } catch (const std::exception &e) {
- zend_throw_error(NULL, "Exception: %s", e.what());
- RETURN_NULL();
- }
- }
- PHP_METHOD (StackTraceTable, values) {
- zend_long stack_id;
- zend_long pid = -1;
- zval name_rv;
- zval *name_zv;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &stack_id, &pid) == FAILURE) {
- RETURN_NULL();
- }
- name_zv = zend_read_property(
- Z_OBJCE_P(getThis()),
- getThis(),
- "name",
- sizeof("name") - 1,
- 1,
- &name_rv
- );
- if (!name_zv || Z_TYPE_P(name_zv) != IS_STRING) {
- zend_throw_error(NULL, "Invalid or missing name property");
- RETURN_NULL();
- }
- sub_object *obj = table_fetch_object(Z_OBJ_P(getThis()));
- if (!obj || !obj->bpf) {
- zend_throw_error(NULL, "Invalid object state");
- RETURN_NULL();
- }
- auto table = obj->bpf->get_stack_table(Z_STRVAL_P(name_zv));
- auto symbols = table.get_stack_symbol((int) stack_id, (int) pid);
- array_init(return_value);
- for (const auto &str: symbols) {
- add_next_index_string(return_value, str.c_str());
- }
- }
- /* }}} */
- /* The previous line is meant for vim and emacs, so it can correctly fold and
- unfold functions in source code. See the corresponding marks just before
- function definition, where the functions purpose is also documented. Please
- follow this convention for the convenience of others editing your code.
- */
- /* {{{ php_ebpf_init_globals
- */
- /* Uncomment this function if you have INI entries
- static void php_ebpf_init_globals(zend_ebpf_globals *ebpf_globals)
- {
- ebpf_globals->global_value = 0;
- ebpf_globals->global_string = NULL;
- }
- */
- /* }}} */
- /* {{{ bpf_class_methods */
- ZEND_BEGIN_ARG_INFO_EX(arginfo_bpf_get, 0, 0, 1)
- ZEND_ARG_INFO(0, name)
- ZEND_END_ARG_INFO()
- static const zend_function_entry bpf_class_methods[] = {
- PHP_ME(Bpf, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
- PHP_ME(Bpf, __get, arginfo_bpf_get, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, get_kprobe_functions, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_kprobe, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_tracepoint, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_raw_tracepoint, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_kfunc, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_lsm, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_uprobe, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, detach_kprobe, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, detach_uprobe, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, trace_print, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, trace_fields, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, get_table, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, perf_buffer_poll, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, get_syscall_fnname, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, load_func, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Bpf, attach_raw_socket, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
- };
- /* }}} */
- /* {{{ table methods */
- static const zend_function_entry perf_event_array_table_methods[] = {
- PHP_ME(PerfEventArrayTable, open_perf_buffer, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
- };
- static const zend_function_entry hash_table_methods[] = {
- PHP_ME(HashTable, values, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(HashTable, clear, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
- };
- static const zend_function_entry array_table_methods[] = {
- PHP_ME(ArrayTable, get_value, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(ArrayTable, print_log2_hist, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(ArrayTable, print_linear_hist, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
- };
- static const zend_function_entry prog_array_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry per_cpu_hash_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry per_cpu_array_table_methods[] = {
- PHP_ME(PerCpuArrayTable, sum_value, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
- };
- static const zend_function_entry lpm_trie_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry stack_trace_table_methods[] = {
- PHP_ME(StackTraceTable, values, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
- };
- static const zend_function_entry lru_hash_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry lru_per_cpu_hash_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry cgroup_array_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry dev_map_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry cpu_map_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry xsk_map_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry map_in_map_array_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry map_in_map_hash_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry queue_stack_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry ring_buf_table_methods[] = {
- PHP_FE_END
- };
- static const zend_function_entry bpf_prog_func_methods[] = {
- PHP_FE_END
- };
- /* }}} */
- PHP_MINIT_FUNCTION (ebpf) {
- zend_class_entry ce;
- memcpy(&bpf_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- bpf_object_handlers.offset = XtOffsetOf(bpf_object, std);
- bpf_object_handlers.free_obj = bpf_free_object;
- REGISTER_BPF_CLASS(ce, bpf_create_object, "Bpf", bpf_ce, bpf_class_methods)
- memcpy(&table_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- table_object_handlers.offset = XtOffsetOf(sub_object, std);
- table_object_handlers.free_obj = table_free_object;
- REGISTER_BPF_CLASS(ce, table_create_object, "PerCpuArrayTable", per_cpu_array_table_ce, per_cpu_array_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "PerfEventArrayTable", perf_event_array_table_ce,
- perf_event_array_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "HashTable", hash_table_ce, hash_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "ArrayTable", array_table_ce, array_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "ProgArrayTable", prog_array_table_ce, prog_array_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "PerCpuHashTable", per_cpu_hash_table_ce, per_cpu_hash_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "LpmTrieTable", lpm_trie_table_ce, lpm_trie_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "StackTraceTable", stack_trace_table_ce, stack_trace_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "LruHashTable", lru_hash_table_ce, lru_hash_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "LruPerCpuHashTable", lru_per_cpu_hash_table_ce,
- lru_per_cpu_hash_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "CgroupArrayTable", cgroup_array_table_ce, cgroup_array_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "DevMapTable", dev_map_table_ce, dev_map_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "CpuMapTable", cpu_map_table_ce, cpu_map_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "XskMapTable", xsk_map_table_ce, xsk_map_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "MapInMapArrayTable", map_in_map_array_table_ce,
- map_in_map_array_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "MapInMapHashTable", map_in_map_hash_table_ce,
- map_in_map_hash_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "QueueStackTable", queue_stack_table_ce, queue_stack_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "RingBufTable", ring_buf_table_ce, ring_buf_table_methods)
- REGISTER_BPF_CLASS(ce, table_create_object, "BPFProgFunction", bpf_prog_func_ce, bpf_prog_func_methods)
- /* Register constants */
- REGISTER_BPF_CONST(SOCKET_FILTER);
- REGISTER_BPF_CONST(KPROBE);
- REGISTER_BPF_CONST(SCHED_CLS);
- REGISTER_BPF_CONST(SCHED_ACT);
- REGISTER_BPF_CONST(TRACEPOINT);
- REGISTER_BPF_CONST(XDP);
- REGISTER_BPF_CONST(PERF_EVENT);
- REGISTER_BPF_CONST(CGROUP_SKB);
- REGISTER_BPF_CONST(CGROUP_SOCK);
- REGISTER_BPF_CONST(LWT_IN);
- REGISTER_BPF_CONST(LWT_OUT);
- REGISTER_BPF_CONST(LWT_XMIT);
- REGISTER_BPF_CONST(SOCK_OPS);
- REGISTER_BPF_CONST(SK_SKB);
- REGISTER_BPF_CONST(CGROUP_DEVICE);
- REGISTER_BPF_CONST(SK_MSG);
- REGISTER_BPF_CONST(RAW_TRACEPOINT);
- REGISTER_BPF_CONST(CGROUP_SOCK_ADDR);
- REGISTER_BPF_CONST(CGROUP_SOCKOPT);
- REGISTER_BPF_CONST(TRACING);
- REGISTER_BPF_CONST(LSM);
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_MSHUTDOWN_FUNCTION
- */
- PHP_MSHUTDOWN_FUNCTION (ebpf) {
- /* uncomment this line if you have INI entries
- UNREGISTER_INI_ENTRIES();
- */
- return SUCCESS;
- }
- /* }}} */
- /* Remove if there's nothing to do at request start */
- /* {{{ PHP_RINIT_FUNCTION
- */
- PHP_RINIT_FUNCTION (ebpf) {
- #if defined(COMPILE_DL_EBPF) && defined(ZTS)
- ZEND_TSRMLS_CACHE_UPDATE();
- #endif
- return SUCCESS;
- }
- /* }}} */
- /* Remove if there's nothing to do at request end */
- /* {{{ PHP_RSHUTDOWN_FUNCTION
- */
- PHP_RSHUTDOWN_FUNCTION (ebpf) {
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_MINFO_FUNCTION
- */
- PHP_MINFO_FUNCTION (ebpf) {
- php_info_print_table_start();
- php_info_print_table_header(2, "ebpf support", "enabled");
- php_info_print_table_end();
- /* Remove comments if you have entries in php.ini
- DISPLAY_INI_ENTRIES();
- */
- }
- /* }}} */
- /* {{{ ebpf_functions[]
- *
- * Every user visible function must have an entry in ebpf_functions[].
- */
- const zend_function_entry ebpf_functions[] = {
- PHP_FE_END /* Must be the last line in ebpf_functions[] */
- };
- /* }}} */
- /* {{{ ebpf_module_entry
- */
- zend_module_entry ebpf_module_entry = {
- STANDARD_MODULE_HEADER,
- "ebpf",
- ebpf_functions,
- PHP_MINIT(ebpf),
- PHP_MSHUTDOWN(ebpf),
- PHP_RINIT(ebpf), /* Replace with NULL if there's nothing to do at request start */
- PHP_RSHUTDOWN(ebpf), /* Replace with NULL if there's nothing to do at request end */
- PHP_MINFO(ebpf),
- PHP_EBPF_VERSION,
- STANDARD_MODULE_PROPERTIES
- };
- /* }}} */
- #ifdef COMPILE_DL_EBPF
- #ifdef ZTS
- ZEND_TSRMLS_CACHE_DEFINE()
- #endif
- ZEND_GET_MODULE(ebpf)
- #endif
- /*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: noet sw=4 ts=4 fdm=marker
- * vim<600: noet sw=4 ts=4
- */
|