| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880 |
- /*
- +----------------------------------------------------------------------+
- | 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>
- #include <iomanip>
- /* 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) {
- zend_long 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();
- }
- try {
- auto table = obj->bpf->get_array_table<uint64_t>(Z_STRVAL_P(name_zv));
- uint64_t val;
- 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();
- }
- RETURN_LONG(val);
- } catch (const std::exception &e) {
- zend_throw_error(NULL, "Exception: %s", e.what());
- RETURN_NULL();
- }
- }
- PHP_METHOD (ArrayTable, print_log2_hist) {
- char *header;
- size_t header_len;
- zval name_rv;
- zval *name_zv;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &header, &header_len) == 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_array_table<uint64_t>(Z_STRVAL_P(name_zv));
- auto vals = table.get_table_offline();
- auto center_text = [](const std::string &text, int width) -> std::string {
- int len = static_cast<int>(text.length());
- if (width <= len) return text;
- int padding = width - len;
- int left = padding / 2;
- int right = padding - left;
- return std::string(left, ' ') + text + std::string(right, ' ');
- };
- auto stars = [](uint64_t val, uint64_t max_val, int width) -> std::string {
- std::string result;
- int limit = std::min(width, static_cast<int>((double) val * width / max_val));
- for (int i = 0; i < limit; ++i) {
- result += '*';
- }
- if (val > max_val && !result.empty()) {
- result.back() = '+';
- }
- return result;
- };
- int idx_max = -1;
- uint64_t val_max = 0;
- for (size_t i = 0; i < vals.size(); ++i) {
- if (vals[i] > 0) {
- idx_max = static_cast<int>(i);
- if (vals[i] > val_max) val_max = vals[i];
- }
- }
- if (idx_max == -1) {
- std::cout << "No data to display." << std::endl;
- RETURN_FALSE
- }
- int stars_max = 40;
- bool long_format = idx_max > 32;
- int col1_width = long_format ? 41 : 27;
- int label_width = col1_width - 2;
- std::cout << center_text(header, label_width) << ": count distribution" << std::endl;
- bool strip_leading_zero = true;
- for (int i = 1; i <= idx_max; ++i) {
- uint64_t low = (1ULL << (i - 1));
- uint64_t high = (1ULL << i) - 1;
- if (low == high) low -= 1;
- uint64_t val = vals[i];
- if (strip_leading_zero && val == 0) {
- continue;
- }
- strip_leading_zero = false;
- std::string bar = stars(val, val_max, stars_max);
- if (long_format) {
- std::cout << std::right << std::setw(20) << low << " -> "
- << std::left << std::setw(20) << high << " : "
- << std::setw(8) << val << "|" << bar << "|" << std::endl;
- } else {
- std::cout << std::right << std::setw(10) << low << " -> "
- << std::left << std::setw(10) << high << " : "
- << std::setw(8) << val << "|" << bar << "|" << std::endl;
- }
- }
- RETURN_FALSE
- }
- PHP_METHOD (ArrayTable, print_linear_hist) {
- char *header;
- size_t header_len;
- zval name_rv;
- zval *name_zv;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &header, &header_len) == 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_array_table<uint64_t>(Z_STRVAL_P(name_zv));
- auto res = table.get_table_offline();
- if (res.empty()) {
- std::cout << "empty histogram" << std::endl;
- RETURN_FALSE
- }
- uint64_t max_val = *std::max_element(res.begin(), res.end());
- if (max_val == 0) max_val = 1;
- std::cout << " " << std::left << std::setw(12) << header
- << std::setw(10) << ": count"
- << " distribution\n";
- int stars_max = 40;
- for (size_t i = 0; i < res.size(); ++i) {
- if (res[i] == 0) continue;
- std::string bar;
- int limit = std::min(stars_max, static_cast<int>((double) res[i] * stars_max / max_val));
- for (int j = 0; j < limit; ++j) bar += '*';
- if (res[i] > max_val && !bar.empty()) bar.back() = '+';
- std::string count_str = ": " + std::to_string(res[i]);
- std::cout << " " << std::left << std::setw(12) << i
- << std::setw(10) << count_str
- << "|" << bar << "|\n";
- }
- }
- 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
- */
|