{"id":14991123,"url":"https://github.com/eunomia-bpf/llvmbpf","last_synced_at":"2025-04-13T11:09:08.556Z","repository":{"id":252527931,"uuid":"840424900","full_name":"eunomia-bpf/llvmbpf","owner":"eunomia-bpf","description":"Userspace eBPF VM with llvm JIT/AOT compiler","archived":false,"fork":false,"pushed_at":"2025-04-10T05:12:16.000Z","size":189,"stargazers_count":64,"open_issues_count":2,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-12T04:14:45.901Z","etag":null,"topics":["aot","ebpf","jit","llvm","runtime","virtual-machine"],"latest_commit_sha":null,"homepage":"https://eunomia.dev/bpftime/llvmbpf/","language":"LLVM","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eunomia-bpf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["yunwei37","Officeyutong"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2024-08-09T17:14:16.000Z","updated_at":"2025-04-10T05:12:21.000Z","dependencies_parsed_at":"2025-04-12T04:14:47.697Z","dependency_job_id":null,"html_url":"https://github.com/eunomia-bpf/llvmbpf","commit_stats":{"total_commits":21,"total_committers":2,"mean_commits":10.5,"dds":0.1428571428571429,"last_synced_commit":"658ba895f2df8891c9219a27299e86524e9e604d"},"previous_names":["eunomia-bpf/llvmbpf"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2Fllvmbpf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2Fllvmbpf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2Fllvmbpf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eunomia-bpf%2Fllvmbpf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eunomia-bpf","download_url":"https://codeload.github.com/eunomia-bpf/llvmbpf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248703198,"owners_count":21148118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aot","ebpf","jit","llvm","runtime","virtual-machine"],"created_at":"2024-09-24T14:21:31.135Z","updated_at":"2025-04-13T11:09:08.531Z","avatar_url":"https://github.com/eunomia-bpf.png","language":"LLVM","funding_links":["https://github.com/sponsors/yunwei37","https://github.com/sponsors/Officeyutong"],"categories":[],"sub_categories":[],"readme":"# Userspace eBPF VM with LLVM JIT/AOT Compiler\n\n[![Build and Test VM](https://github.com/eunomia-bpf/llvmbpf/actions/workflows/test-vm.yml/badge.svg)](https://github.com/eunomia-bpf/llvmbpf/actions/workflows/test-vm.yml)\n[![codecov](https://codecov.io/gh/eunomia-bpf/llvmbpf/graph/badge.svg?token=ZQXHpOwDa1)](https://codecov.io/gh/eunomia-bpf/llvmbpf)\n\nA high-performance, multi-architecture JIT/AOT compiler and virtual machine (VM) based on LLVM.\n\nThis component is part of the [bpftime](https://github.com/eunomia-bpf/bpftime) project but focuses solely on the core VM. It offers the following capabilities:\n\n- Operates as `a standalone eBPF VM library` or compiler tool.\n- Compiles eBPF bytecode into LLVM IR files.\n- Compiles eBPF ELF files into AOTed native code ELF object files, which can be linked like C-compiled objects or loaded into llvmbpf.\n- Loads and executes AOT-compiled ELF object files within the eBPF runtime.\n- Supports eBPF helpers and maps lddw functions.\n\nThis library is optimized for performance, flexibility, and minimal dependencies. It does not include maps implement, helpers, verifiers, or loaders for eBPF applications, making it suitable as a lightweight, high-performance library.\n\nFor a comprehensive userspace eBPF runtime that includes support for maps, helpers, and seamless execution of Uprobe, syscall trace, XDP, and other eBPF programs—similar to kernel functionality but in userspace—please refer to the [bpftime](https://github.com/eunomia-bpf/bpftime) project.\n\n- [Userspace eBPF VM with LLVM JIT/AOT Compiler](#userspace-ebpf-vm-with-llvm-jitaot-compiler)\n  - [build project](#build-project)\n  - [Usage](#usage)\n    - [Use llvmbpf as a library](#use-llvmbpf-as-a-library)\n    - [Use llvmbpf as a AOT compiler](#use-llvmbpf-as-a-aot-compiler)\n    - [load eBPF bytecode from ELF file](#load-ebpf-bytecode-from-elf-file)\n    - [Maps and data relocation support](#maps-and-data-relocation-support)\n    - [Build into standalone binary for deployment](#build-into-standalone-binary-for-deployment)\n  - [optimizaion](#optimizaion)\n    - [inline the maps and helper function](#inline-the-maps-and-helper-function)\n    - [Use original LLVM IR from C code](#use-original-llvm-ir-from-c-code)\n  - [Test](#test)\n    - [Unit test](#unit-test)\n    - [Test with bpf-conformance](#test-with-bpf-conformance)\n  - [License](#license)\n\n## build project\n\n```sh\nsudo apt install llvm-15-dev libzstd-dev\ncmake -B build -DCMAKE_BUILD_TYPE=Release\ncmake --build build --target all -j\n```\n\n## Usage\n\n### Use llvmbpf as a library\n\nSee [example](example/main.cpp) of how to use the library as a vm:\n\n```cpp\nvoid run_ebpf_prog(const void *code, size_t code_len)\n{\n    uint64_t res = 0;\n    llvmbpf_vm vm;\n\n    res = vm.load_code(code, code_len);\n    if (res) {\n        return;\n    }\n    vm.register_external_function(2, \"print\", (void *)ffi_print_func);\n    auto func = vm.compile();\n    if (!func) {\n        return;\n    }\n    int err = vm.exec(\u0026bpf_mem, sizeof(bpf_mem), res);\n    if (err != 0) {\n        return;\n    }\n    printf(\"res = %\" PRIu64 \"\\n\", res);\n}\n```\n\n### Use llvmbpf as a AOT compiler\n\nBuild with cli:\n\n```sh\nsudo apt-get install libelf1 libelf-dev\ncmake -B build  -DBUILD_LLVM_AOT_CLI=1 \n```\n\nYou can use the cli to generate the LLVM IR from eBPF bytecode:\n\n```console\n# ./build/cli/bpftime-vm build .github/assets/sum.bpf.o -emit-llvm \u003e test.bpf.ll\n# opt -O3 -S test.bpf.ll -opaque-pointers  -o test.opt.ll\n# cat test.opt.ll\n; ModuleID = 'test.bpf.ll'\nsource_filename = \"bpf-jit\"\n\n; Function Attrs: nofree norecurse nosync nounwind memory(read, inaccessiblemem: none)\ndefine i64 @bpf_main(ptr %0, i64 %1) local_unnamed_addr #0 {\nsetupBlock:\n  %2 = ptrtoint ptr %0 to i64\n  %3 = load i32, ptr %0, align 4\n  %4 = icmp slt i32 %3, 1\n  br i1 %4, label %bb_inst_30, label %bb_inst_15\n\nbb_inst_15:                                       ; preds = %setupBlock, %bb_inst_15\n  %storemerge32 = phi i32 [ %11, %bb_inst_15 ], [ 1, %setupBlock ]\n  %stackBegin29.sroa.2.031 = phi i32 [ %10, %bb_inst_15 ], [ 0, %setupBlock ]\n  %5 = sext i32 %storemerge32 to i64\n  %6 = shl nsw i64 %5, 2\n  %7 = add i64 %6, %2\n  %8 = inttoptr i64 %7 to ptr\n  %9 = load i32, ptr %8, align 4\n  %10 = add i32 %9, %stackBegin29.sroa.2.031\n  %11 = add i32 %storemerge32, 1\n  %12 = icmp sgt i32 %11, %3\n  br i1 %12, label %bb_inst_30, label %bb_inst_15\n\nbb_inst_30:                                       ; preds = %bb_inst_15, %setupBlock\n  %stackBegin29.sroa.2.0.lcssa = phi i32 [ 0, %setupBlock ], [ %10, %bb_inst_15 ]\n  %13 = zext i32 %stackBegin29.sroa.2.0.lcssa to i64\n  ret i64 %13\n}\n\nattributes #0 = { nofree norecurse nosync nounwind memory(read, inaccessiblemem: none) }\n```\n\nAOT Compile a eBPF program:\n\n```console\n# ./build/cli/bpftime-vm build .github/assets/sum.bpf.o\n[2024-08-10 14:54:06.453] [info] [main.cpp:56] Processing program test\n[2024-08-10 14:54:06.479] [info] [main.cpp:69] Program test written to ./test.o\n```\n\nLoad and run a AOTed eBPF program:\n\n```console\n# echo \"AwAAAAEAAAACAAAAAwAAAA==\" | base64 -d \u003e test.bin\n# ./build/cli/bpftime-vm run test.o test.bin\n[2024-08-10 14:57:16.986] [info] [llvm_jit_context.cpp:392] LLVM-JIT: Loading aot object\n[2024-08-10 14:57:16.991] [info] [main.cpp:136] Program executed successfully. Return value: 6\n```\n\nSee [Build into standalone binary for deployment](#build-into-standalone-binary-for-deployment) for more details.\n\n### load eBPF bytecode from ELF file\n\nYou can use llvmbpf together with libbpf to load the eBPF bytecode directly from `bpf.o` ELF file. For example:\n\n```c\n  bpf_object *obj = bpf_object__open(ebpf_elf.c_str());\n  if (!obj) {\n    return 1;\n  }\n  std::unique_ptr\u003cbpf_object, decltype(\u0026bpf_object__close)\u003e elf(\n    obj, bpf_object__close);\n\n  bpf_program *prog;\n  for ((prog) = bpf_object__next_program((elf.get()), __null);\n       (prog) != __null;\n       (prog) = bpf_object__next_program((elf.get()), (prog))) {\n    const char *name = bpf_program__name(prog);\n    llvmbpf_vm vm;\n\n    vm.load_code((const void *)bpf_program__insns(prog),\n         (uint32_t)bpf_program__insn_cnt(prog) * 8);\n  ...\n  }\n```\n\nFor complete code example, please refer to [cli](cli).\n\nHowever, the `bpf.o` ELF file has no map and data relocation support. We would recommend using the bpftime to load and relocation the eBPF bytecode from ELF file. This include:\n\n- Write a loader like normal kernel eBPF loader to load the eBPF bytecode, you can find a example [here](https://github.com/eunomia-bpf/bpftime/blob/master/example/xdp-counter/xdp-counter.c).\n- The loader will use the libbpf, which support:\n  - Relocation for map. The map id will be allocated by the loader and bpftime, you can use the map id to access map through the helpers.\n  - The data can be accessed through the lddw helper function.\n- After the loader load the eBPF bytecode and complete the relocation, you can use the [bpftimetool](https://eunomia.dev/zh/bpftime/documents/bpftimetool/) to dump the map information and eBPF bytecode.\n\n### Maps and data relocation support\n\nbpftime already has maps and data relocation support. The easiest way to use it is just use bpftime and write the loader and eBPF program like kernel eBPF. The `llvmbpf` libray provide a approach to interact with the maps.\n\nSee [example/maps.cpp](example/maps.cpp) of how to use the library as a vm and works with maps:\n\nThe eBPF can work with maps in two ways:\n\n- Using helper functions to access the maps, like `bpf_map_lookup_elem`, `bpf_map_update_elem`, etc.\n- Using maps as global variables in the eBPF program, and access the maps directly.\n\nFor a eBPF program like [https://github.com/eunomia-bpf/bpftime/blob/master/example/xdp-counter/](https://github.com/eunomia-bpf/bpftime/blob/master/example/xdp-counter/):\n\n```c\n// use map type define\nstruct {\n  __uint(type, BPF_MAP_TYPE_ARRAY);\n  __type(key, __u32);\n  __type(value, __u32);\n  __uint(max_entries, CTRL_ARRAY_SIZE);\n} ctl_array SEC(\".maps\");\n\n// use global variable define\n__u64 cntrs_array[CNTRS_ARRAY_SIZE];\n\nSEC(\"xdp\")\nint xdp_pass(struct xdp_md* ctx) {\n  void* data_end = (void*)(long)ctx-\u003edata_end;\n  void* data = (void*)(long)ctx-\u003edata;\n  __u32 ctl_flag_pos = 0;\n  __u32 cntr_pos = 0;\n\n  // access maps with helpers\n  __u32* flag = bpf_map_lookup_elem(\u0026ctl_array, \u0026ctl_flag_pos);\n  if (!flag || (*flag != 0)) {\n    return XDP_PASS;\n  };\n\n  // access maps with global variables\n  cntrs_array[cntr_pos]++;\n\n  if (data + sizeof(struct ethhdr) \u003e data_end)\n    return XDP_DROP;\n  swap_src_dst_mac(data);\n  return XDP_TX;\n}\n```\n\nWe can define the map and access them like:\n\n```cpp\nuint32_t ctl_array[2] = { 0, 0 };\nuint64_t cntrs_array[2] = { 0, 0 };\n\nvoid *bpf_map_lookup_elem(uint64_t map_fd, void *key)\n{\n  std::cout \u003c\u003c \"bpf_map_lookup_elem \" \u003c\u003c map_fd \u003c\u003c std::endl;\n  if (map_fd == 5) {\n    return \u0026ctl_array[*(uint32_t *)key];\n  } else if (map_fd == 6) {\n    return \u0026cntrs_array[*(uint32_t *)key];\n  } else {\n    return nullptr;\n  }\n  return 0;\n}\n\nuint64_t map_by_fd(uint32_t fd)\n{\n  std::cout \u003c\u003c \"map_by_fd \" \u003c\u003c fd \u003c\u003c std::endl;\n  return fd;\n}\n\nuint64_t map_val(uint64_t val)\n{\n  std::cout \u003c\u003c \"map_val \" \u003c\u003c val \u003c\u003c std::endl;\n  if (val == 5) {\n    return (uint64_t)(void *)ctl_array;\n  } else if (val == 6) {\n    return (uint64_t)(void *)cntrs_array;\n  } else {\n    return 0;\n  }\n}\n\nint main(int argc, char *argv[])\n{\n  auto code = xdp_counter_bytecode;\n  size_t code_len = sizeof(xdp_counter_bytecode) - 1;\n  uint64_t res = 0;\n  llvmbpf_vm vm;\n\n  res = vm.load_code(code, code_len);\n  if (res) {\n    std::cout \u003c\u003c vm.get_error_message() \u003c\u003c std::endl;\n    exit(1);\n  }\n  vm.register_external_function(1, \"bpf_map_lookup_elem\",\n              (void *)bpf_map_lookup_elem);\n  // set the lddw helpers for accessing maps\n  vm.set_lddw_helpers(map_by_fd, nullptr, map_val, nullptr, nullptr);\n  auto func = vm.compile();\n  if (!func) {\n    std::cout \u003c\u003c vm.get_error_message() \u003c\u003c std::endl;\n    exit(1);\n  }\n  // Map value (counter) should be 0\n  std::cout \u003c\u003c \"cntrs_array[0] = \" \u003c\u003c cntrs_array[0] \u003c\u003c std::endl;\n  int err = vm.exec(\u0026bpf_mem, sizeof(bpf_mem), res);\n  std::cout \u003c\u003c \"\\nreturn value = \" \u003c\u003c res \u003c\u003c std::endl;\n  // counter should be 1\n  std::cout \u003c\u003c \"cntrs_array[0] = \" \u003c\u003c cntrs_array[0] \u003c\u003c std::endl;\n  ....\n}\n```\n\nReference:\n\n- \u003chttps://prototype-kernel.readthedocs.io/en/latest/bpf/ebpf_maps.html\u003e\n- \u003chttps://www.ietf.org/archive/id/draft-ietf-bpf-isa-00.html#name-64-bit-immediate-instructio\u003e\n\n### Build into standalone binary for deployment\n\nYou can build the eBPF program into a standalone binary, which does not rely on any external libraries, and can be exec like nomal c code with helper and maps support.\n\nThis can help:\n\n- Easily deploy the eBPF program to any machine without the need to install any dependencies.\n- Avoid the overhead of loading the eBPF bytecode and maps at runtime.\n- Suitable for microcontroller or embedded systems, which does not have a OS.\n\nTake [https://github.com/eunomia-bpf/bpftime/blob/master/example/xdp-counter/](https://github.com/eunomia-bpf/bpftime/blob/master/example/xdp-counter/) as an example:\n\nIn the bpftime project:\n\n```sh\n# load the eBPF program with bpftime\nLD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so example/xdp-counter/xdp-counter example/xdp-counter/.output/xdp-counter.bpf.o veth1\n# dump the map and eBPF bytecode define\n./build/tools/bpftimetool/bpftimetool export res.json\n# build the eBPF program into llvm IR\n./build/tools/aot/bpftime-aot compile --emit_llvm 1\u003exdp-counter.ll\n```\n\nYou can see [example/xdp-counter.json](example/xdp-counter.json) for an example json file dump by bpftime.\n\nThe result xdp-counter.ll can be found in [example/standalone/xdp-counter.ll](example/standalone/xdp-counter.ll).\n\nThen you can write a C code and compile it with the llvm IR:\n\n```c\n#include \u003cstdint.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cinttypes.h\u003e\n\nint bpf_main(void* ctx, uint64_t size);\n\nuint32_t ctl_array[2] = { 0, 0 };\nuint64_t cntrs_array[2] = { 0, 0 };\n\nvoid *_bpf_helper_ext_0001(uint64_t map_fd, void *key)\n{\n  printf(\"bpf_map_lookup_elem %lu\\n\", map_fd);\n  if (map_fd == 5) {\n    return \u0026ctl_array[*(uint32_t *)key];\n  } else if (map_fd == 6) {\n    return \u0026cntrs_array[*(uint32_t *)key];\n  } else {\n    return NULL;\n  }\n  return 0;\n}\n\nvoid* __lddw_helper_map_val(uint64_t val)\n{\n    printf(\"map_val %lu\\n\", val);\n    if (val == 5) {\n        return (void *)ctl_array;\n    } else if (val == 6) {\n        return (void *)cntrs_array;\n    } else {\n        return NULL;\n    }\n}\n\nuint8_t bpf_mem[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };\n\nint main() {\n    printf(\"The value of cntrs_array[0] is %\" PRIu64 \"\\n\", cntrs_array[0]);\n    printf(\"calling ebpf program...\\n\");\n    bpf_main(bpf_mem, sizeof(bpf_mem));\n    printf(\"The value of cntrs_array[0] is %\" PRIu64 \"\\n\", cntrs_array[0]);\n    printf(\"calling ebpf program...\\n\");\n    bpf_main(bpf_mem, sizeof(bpf_mem));\n    printf(\"The value of cntrs_array[0] is %\" PRIu64 \"\\n\", cntrs_array[0]);\n    return 0;\n}\n```\n\nCompile the C code with the llvm IR:\n\n```sh\nclang -g main.c xdp-counter.ll -o standalone \n```\n\nAnd you can run the `standalone` eBPF program directly.\n\n## optimizaion\n\nBased on the AOT compiler, we can apply some optimization strategies:\n\n### inline the maps and helper function\n\nInline the maps and helper function into the eBPF program, so that the eBPF program can be optimized with `const propagation`, `dead code elimination`, etc by the LLVM optimizer. llvmbpf can also eliminate the cost of function calls.\n\nPrepare a C code:\n\n```c\n\nuint32_t ctl_array[2] = { 0, 0 };\nuint64_t cntrs_array[2] = { 0, 0 };\n\nvoid *_bpf_helper_ext_0001(uint64_t map_fd, void *key)\n{\n  if (map_fd == 5) {\n    return \u0026ctl_array[*(uint32_t *)key];\n  } else if (map_fd == 6) {\n    return \u0026cntrs_array[*(uint32_t *)key];\n  } else {\n    return NULL;\n  }\n  return 0;\n}\n\nvoid* __lddw_helper_map_val(uint64_t val)\n{\n    if (val == 5) {\n        return (void *)ctl_array;\n    } else if (val == 6) {\n        return (void *)cntrs_array;\n    } else {\n        return NULL;\n    }\n}\n```\n\nMerge the modules with `llvm-link` and inline them:\n\n```sh\nclang -S -O3 -emit-llvm libmap.c -o libmap.ll\nllvm-link -S -o xdp-counter-inline.ll xdp-counter.ll libmap.ll\nopt --always-inline -S xdp-counter-inline.ll -o xdp-counter-inline.ll\nclang -O3 -g -c xdp-counter-inline.ll -o inline.o\n```\n\nRun the code with cli:\n\n```c\n./build/cli/bpftime-vm run example/inline/inline.o test.bin\n```\n\nOr you can compile as standalone binary and link with the C code:\n\n```console\n$ clang -O3 example/inline/inline.o example/inline/main.c -o inline\n$ /workspaces/llvmbpf/inline\ncalling ebpf program...\nreturn value = 1\n```\n\n### Use original LLVM IR from C code\n\neBPF is a instruction set define for verification, but may not be the best for performance.\n\nllvmbpf also support using the original LLVM IR from C code. See [example/load-llvm-ir](example/load-llvm-ir) for an example. You can:\n\n- Compile the C code to eBPF for verify\n- Compile the C code to LLVM IR and native code for execution in the VM.\n\nThe C code:\n\n```c\nint _bpf_helper_ext_0006(const char *fmt, ... );\n\nint bpf_main(void* ctx, int size) {\n    _bpf_helper_ext_0006(\"hello world: %d\\n\", size);\n    return 0;\n}\n```\n\nYou can compile it with `clang -g -c bpf_module.c -o bpf_module.o`, and Run the code with cli:\n\n```c\n./build/cli/bpftime-vm run example/load-llvm-ir/bpf_module.o test.bin\n```\n\n## Test\n\n### Unit test\n\nCompile:\n\n```sh\nsudo apt install llvm-15-dev libzstd-dev\ncmake -B build -DCMAKE_BUILD_TYPE=Debug -DBPFTIME_ENABLE_UNIT_TESTING=1 -DBPFTIME_ENABLE_CODE_COVERAGE=1\ncmake --build build --target all -j\n```\n\nThe unit tests can be found at `build/test/unit-test/llvm_jit_tests`.\n\n### Test with bpf-conformance\n\nSee the CI in [.github/workflows/bpf_conformance.yml](.github/workflows/bpf_conformance.yml) for how to run the bpf-conformance tests.\n\nThe test result can be found in \u003chttps://eunomia-bpf.github.io/llvmbpf/bpf_conformance_results.txt\u003e\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feunomia-bpf%2Fllvmbpf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feunomia-bpf%2Fllvmbpf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feunomia-bpf%2Fllvmbpf/lists"}