├── .clang-format ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-BSD2 ├── LICENSE-LGPL21 ├── README.md ├── examples ├── bashreadline │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── bpf │ │ ├── bashreadline.bpf.c │ │ ├── trace_helpers.c │ │ └── trace_helpers.h │ │ └── main.rs └── profiler │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ ├── bpf │ └── profiler.bpf.c │ └── main.rs └── libbpf-async ├── Cargo.toml └── src ├── lib.rs └── ringbuf.rs /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # clang-format configuration file. Intended for clang-format >= 4. 4 | # 5 | # For more information, see: 6 | # 7 | # Documentation/process/clang-format.rst 8 | # https://clang.llvm.org/docs/ClangFormat.html 9 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 10 | # 11 | --- 12 | AccessModifierOffset: -4 13 | AlignAfterOpenBracket: Align 14 | AlignConsecutiveAssignments: false 15 | AlignConsecutiveDeclarations: false 16 | #AlignEscapedNewlines: Left # Unknown to clang-format-4.0 17 | AlignOperands: true 18 | AlignTrailingComments: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | AllowShortBlocksOnASingleLine: false 21 | AllowShortCaseLabelsOnASingleLine: false 22 | AllowShortFunctionsOnASingleLine: None 23 | AllowShortIfStatementsOnASingleLine: false 24 | AllowShortLoopsOnASingleLine: false 25 | AlwaysBreakAfterDefinitionReturnType: None 26 | AlwaysBreakAfterReturnType: None 27 | AlwaysBreakBeforeMultilineStrings: false 28 | AlwaysBreakTemplateDeclarations: false 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterClass: false 33 | AfterControlStatement: false 34 | AfterEnum: false 35 | AfterFunction: true 36 | AfterNamespace: true 37 | AfterObjCDeclaration: false 38 | AfterStruct: false 39 | AfterUnion: false 40 | #AfterExternBlock: false # Unknown to clang-format-5.0 41 | BeforeCatch: false 42 | BeforeElse: false 43 | IndentBraces: false 44 | #SplitEmptyFunction: true # Unknown to clang-format-4.0 45 | #SplitEmptyRecord: true # Unknown to clang-format-4.0 46 | #SplitEmptyNamespace: true # Unknown to clang-format-4.0 47 | BreakBeforeBinaryOperators: None 48 | BreakBeforeBraces: Custom 49 | #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializersBeforeComma: false 52 | #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 53 | BreakAfterJavaFieldAnnotations: false 54 | BreakStringLiterals: false 55 | ColumnLimit: 80 56 | CommentPragmas: '^ IWYU pragma:' 57 | #CompactNamespaces: false # Unknown to clang-format-4.0 58 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 59 | ConstructorInitializerIndentWidth: 8 60 | ContinuationIndentWidth: 8 61 | Cpp11BracedListStyle: false 62 | DerivePointerAlignment: false 63 | DisableFormat: false 64 | ExperimentalAutoDetectBinPacking: false 65 | #FixNamespaceComments: false # Unknown to clang-format-4.0 66 | 67 | # Taken from: 68 | # git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ 69 | # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ 70 | # | sort | uniq 71 | ForEachMacros: 72 | - 'apei_estatus_for_each_section' 73 | - 'ata_for_each_dev' 74 | - 'ata_for_each_link' 75 | - '__ata_qc_for_each' 76 | - 'ata_qc_for_each' 77 | - 'ata_qc_for_each_raw' 78 | - 'ata_qc_for_each_with_internal' 79 | - 'ax25_for_each' 80 | - 'ax25_uid_for_each' 81 | - '__bio_for_each_bvec' 82 | - 'bio_for_each_bvec' 83 | - 'bio_for_each_bvec_all' 84 | - 'bio_for_each_integrity_vec' 85 | - '__bio_for_each_segment' 86 | - 'bio_for_each_segment' 87 | - 'bio_for_each_segment_all' 88 | - 'bio_list_for_each' 89 | - 'bip_for_each_vec' 90 | - 'bitmap_for_each_clear_region' 91 | - 'bitmap_for_each_set_region' 92 | - 'blkg_for_each_descendant_post' 93 | - 'blkg_for_each_descendant_pre' 94 | - 'blk_queue_for_each_rl' 95 | - 'bond_for_each_slave' 96 | - 'bond_for_each_slave_rcu' 97 | - 'bpf_for_each_spilled_reg' 98 | - 'btree_for_each_safe128' 99 | - 'btree_for_each_safe32' 100 | - 'btree_for_each_safe64' 101 | - 'btree_for_each_safel' 102 | - 'card_for_each_dev' 103 | - 'cgroup_taskset_for_each' 104 | - 'cgroup_taskset_for_each_leader' 105 | - 'cpufreq_for_each_entry' 106 | - 'cpufreq_for_each_entry_idx' 107 | - 'cpufreq_for_each_valid_entry' 108 | - 'cpufreq_for_each_valid_entry_idx' 109 | - 'css_for_each_child' 110 | - 'css_for_each_descendant_post' 111 | - 'css_for_each_descendant_pre' 112 | - 'device_for_each_child_node' 113 | - 'displayid_iter_for_each' 114 | - 'dma_fence_chain_for_each' 115 | - 'do_for_each_ftrace_op' 116 | - 'drm_atomic_crtc_for_each_plane' 117 | - 'drm_atomic_crtc_state_for_each_plane' 118 | - 'drm_atomic_crtc_state_for_each_plane_state' 119 | - 'drm_atomic_for_each_plane_damage' 120 | - 'drm_client_for_each_connector_iter' 121 | - 'drm_client_for_each_modeset' 122 | - 'drm_connector_for_each_possible_encoder' 123 | - 'drm_for_each_bridge_in_chain' 124 | - 'drm_for_each_connector_iter' 125 | - 'drm_for_each_crtc' 126 | - 'drm_for_each_crtc_reverse' 127 | - 'drm_for_each_encoder' 128 | - 'drm_for_each_encoder_mask' 129 | - 'drm_for_each_fb' 130 | - 'drm_for_each_legacy_plane' 131 | - 'drm_for_each_plane' 132 | - 'drm_for_each_plane_mask' 133 | - 'drm_for_each_privobj' 134 | - 'drm_mm_for_each_hole' 135 | - 'drm_mm_for_each_node' 136 | - 'drm_mm_for_each_node_in_range' 137 | - 'drm_mm_for_each_node_safe' 138 | - 'flow_action_for_each' 139 | - 'for_each_acpi_dev_match' 140 | - 'for_each_active_dev_scope' 141 | - 'for_each_active_drhd_unit' 142 | - 'for_each_active_iommu' 143 | - 'for_each_aggr_pgid' 144 | - 'for_each_available_child_of_node' 145 | - 'for_each_bio' 146 | - 'for_each_board_func_rsrc' 147 | - 'for_each_bvec' 148 | - 'for_each_card_auxs' 149 | - 'for_each_card_auxs_safe' 150 | - 'for_each_card_components' 151 | - 'for_each_card_dapms' 152 | - 'for_each_card_pre_auxs' 153 | - 'for_each_card_prelinks' 154 | - 'for_each_card_rtds' 155 | - 'for_each_card_rtds_safe' 156 | - 'for_each_card_widgets' 157 | - 'for_each_card_widgets_safe' 158 | - 'for_each_cgroup_storage_type' 159 | - 'for_each_child_of_node' 160 | - 'for_each_clear_bit' 161 | - 'for_each_clear_bit_from' 162 | - 'for_each_cmsghdr' 163 | - 'for_each_compatible_node' 164 | - 'for_each_component_dais' 165 | - 'for_each_component_dais_safe' 166 | - 'for_each_comp_order' 167 | - 'for_each_console' 168 | - 'for_each_cpu' 169 | - 'for_each_cpu_and' 170 | - 'for_each_cpu_not' 171 | - 'for_each_cpu_wrap' 172 | - 'for_each_dapm_widgets' 173 | - 'for_each_dev_addr' 174 | - 'for_each_dev_scope' 175 | - 'for_each_dma_cap_mask' 176 | - 'for_each_dpcm_be' 177 | - 'for_each_dpcm_be_rollback' 178 | - 'for_each_dpcm_be_safe' 179 | - 'for_each_dpcm_fe' 180 | - 'for_each_drhd_unit' 181 | - 'for_each_dss_dev' 182 | - 'for_each_dtpm_table' 183 | - 'for_each_efi_memory_desc' 184 | - 'for_each_efi_memory_desc_in_map' 185 | - 'for_each_element' 186 | - 'for_each_element_extid' 187 | - 'for_each_element_id' 188 | - 'for_each_endpoint_of_node' 189 | - 'for_each_evictable_lru' 190 | - 'for_each_fib6_node_rt_rcu' 191 | - 'for_each_fib6_walker_rt' 192 | - 'for_each_free_mem_pfn_range_in_zone' 193 | - 'for_each_free_mem_pfn_range_in_zone_from' 194 | - 'for_each_free_mem_range' 195 | - 'for_each_free_mem_range_reverse' 196 | - 'for_each_func_rsrc' 197 | - 'for_each_hstate' 198 | - 'for_each_if' 199 | - 'for_each_iommu' 200 | - 'for_each_ip_tunnel_rcu' 201 | - 'for_each_irq_nr' 202 | - 'for_each_link_codecs' 203 | - 'for_each_link_cpus' 204 | - 'for_each_link_platforms' 205 | - 'for_each_lru' 206 | - 'for_each_matching_node' 207 | - 'for_each_matching_node_and_match' 208 | - 'for_each_member' 209 | - 'for_each_memcg_cache_index' 210 | - 'for_each_mem_pfn_range' 211 | - '__for_each_mem_range' 212 | - 'for_each_mem_range' 213 | - '__for_each_mem_range_rev' 214 | - 'for_each_mem_range_rev' 215 | - 'for_each_mem_region' 216 | - 'for_each_migratetype_order' 217 | - 'for_each_msi_entry' 218 | - 'for_each_msi_entry_safe' 219 | - 'for_each_net' 220 | - 'for_each_net_continue_reverse' 221 | - 'for_each_netdev' 222 | - 'for_each_netdev_continue' 223 | - 'for_each_netdev_continue_rcu' 224 | - 'for_each_netdev_continue_reverse' 225 | - 'for_each_netdev_feature' 226 | - 'for_each_netdev_in_bond_rcu' 227 | - 'for_each_netdev_rcu' 228 | - 'for_each_netdev_reverse' 229 | - 'for_each_netdev_safe' 230 | - 'for_each_net_rcu' 231 | - 'for_each_new_connector_in_state' 232 | - 'for_each_new_crtc_in_state' 233 | - 'for_each_new_mst_mgr_in_state' 234 | - 'for_each_new_plane_in_state' 235 | - 'for_each_new_private_obj_in_state' 236 | - 'for_each_node' 237 | - 'for_each_node_by_name' 238 | - 'for_each_node_by_type' 239 | - 'for_each_node_mask' 240 | - 'for_each_node_state' 241 | - 'for_each_node_with_cpus' 242 | - 'for_each_node_with_property' 243 | - 'for_each_nonreserved_multicast_dest_pgid' 244 | - 'for_each_of_allnodes' 245 | - 'for_each_of_allnodes_from' 246 | - 'for_each_of_cpu_node' 247 | - 'for_each_of_pci_range' 248 | - 'for_each_old_connector_in_state' 249 | - 'for_each_old_crtc_in_state' 250 | - 'for_each_old_mst_mgr_in_state' 251 | - 'for_each_oldnew_connector_in_state' 252 | - 'for_each_oldnew_crtc_in_state' 253 | - 'for_each_oldnew_mst_mgr_in_state' 254 | - 'for_each_oldnew_plane_in_state' 255 | - 'for_each_oldnew_plane_in_state_reverse' 256 | - 'for_each_oldnew_private_obj_in_state' 257 | - 'for_each_old_plane_in_state' 258 | - 'for_each_old_private_obj_in_state' 259 | - 'for_each_online_cpu' 260 | - 'for_each_online_node' 261 | - 'for_each_online_pgdat' 262 | - 'for_each_pci_bridge' 263 | - 'for_each_pci_dev' 264 | - 'for_each_pci_msi_entry' 265 | - 'for_each_pcm_streams' 266 | - 'for_each_physmem_range' 267 | - 'for_each_populated_zone' 268 | - 'for_each_possible_cpu' 269 | - 'for_each_present_cpu' 270 | - 'for_each_prime_number' 271 | - 'for_each_prime_number_from' 272 | - 'for_each_process' 273 | - 'for_each_process_thread' 274 | - 'for_each_prop_codec_conf' 275 | - 'for_each_prop_dai_codec' 276 | - 'for_each_prop_dai_cpu' 277 | - 'for_each_prop_dlc_codecs' 278 | - 'for_each_prop_dlc_cpus' 279 | - 'for_each_prop_dlc_platforms' 280 | - 'for_each_property_of_node' 281 | - 'for_each_registered_fb' 282 | - 'for_each_requested_gpio' 283 | - 'for_each_requested_gpio_in_range' 284 | - 'for_each_reserved_mem_range' 285 | - 'for_each_reserved_mem_region' 286 | - 'for_each_rtd_codec_dais' 287 | - 'for_each_rtd_components' 288 | - 'for_each_rtd_cpu_dais' 289 | - 'for_each_rtd_dais' 290 | - 'for_each_set_bit' 291 | - 'for_each_set_bit_from' 292 | - 'for_each_set_clump8' 293 | - 'for_each_sg' 294 | - 'for_each_sg_dma_page' 295 | - 'for_each_sg_page' 296 | - 'for_each_sgtable_dma_page' 297 | - 'for_each_sgtable_dma_sg' 298 | - 'for_each_sgtable_page' 299 | - 'for_each_sgtable_sg' 300 | - 'for_each_sibling_event' 301 | - 'for_each_subelement' 302 | - 'for_each_subelement_extid' 303 | - 'for_each_subelement_id' 304 | - '__for_each_thread' 305 | - 'for_each_thread' 306 | - 'for_each_unicast_dest_pgid' 307 | - 'for_each_vsi' 308 | - 'for_each_wakeup_source' 309 | - 'for_each_zone' 310 | - 'for_each_zone_zonelist' 311 | - 'for_each_zone_zonelist_nodemask' 312 | - 'fwnode_for_each_available_child_node' 313 | - 'fwnode_for_each_child_node' 314 | - 'fwnode_graph_for_each_endpoint' 315 | - 'gadget_for_each_ep' 316 | - 'genradix_for_each' 317 | - 'genradix_for_each_from' 318 | - 'hash_for_each' 319 | - 'hash_for_each_possible' 320 | - 'hash_for_each_possible_rcu' 321 | - 'hash_for_each_possible_rcu_notrace' 322 | - 'hash_for_each_possible_safe' 323 | - 'hash_for_each_rcu' 324 | - 'hash_for_each_safe' 325 | - 'hctx_for_each_ctx' 326 | - 'hlist_bl_for_each_entry' 327 | - 'hlist_bl_for_each_entry_rcu' 328 | - 'hlist_bl_for_each_entry_safe' 329 | - 'hlist_for_each' 330 | - 'hlist_for_each_entry' 331 | - 'hlist_for_each_entry_continue' 332 | - 'hlist_for_each_entry_continue_rcu' 333 | - 'hlist_for_each_entry_continue_rcu_bh' 334 | - 'hlist_for_each_entry_from' 335 | - 'hlist_for_each_entry_from_rcu' 336 | - 'hlist_for_each_entry_rcu' 337 | - 'hlist_for_each_entry_rcu_bh' 338 | - 'hlist_for_each_entry_rcu_notrace' 339 | - 'hlist_for_each_entry_safe' 340 | - 'hlist_for_each_entry_srcu' 341 | - '__hlist_for_each_rcu' 342 | - 'hlist_for_each_safe' 343 | - 'hlist_nulls_for_each_entry' 344 | - 'hlist_nulls_for_each_entry_from' 345 | - 'hlist_nulls_for_each_entry_rcu' 346 | - 'hlist_nulls_for_each_entry_safe' 347 | - 'i3c_bus_for_each_i2cdev' 348 | - 'i3c_bus_for_each_i3cdev' 349 | - 'ide_host_for_each_port' 350 | - 'ide_port_for_each_dev' 351 | - 'ide_port_for_each_present_dev' 352 | - 'idr_for_each_entry' 353 | - 'idr_for_each_entry_continue' 354 | - 'idr_for_each_entry_continue_ul' 355 | - 'idr_for_each_entry_ul' 356 | - 'in_dev_for_each_ifa_rcu' 357 | - 'in_dev_for_each_ifa_rtnl' 358 | - 'inet_bind_bucket_for_each' 359 | - 'inet_lhash2_for_each_icsk_rcu' 360 | - 'key_for_each' 361 | - 'key_for_each_safe' 362 | - 'klp_for_each_func' 363 | - 'klp_for_each_func_safe' 364 | - 'klp_for_each_func_static' 365 | - 'klp_for_each_object' 366 | - 'klp_for_each_object_safe' 367 | - 'klp_for_each_object_static' 368 | - 'kunit_suite_for_each_test_case' 369 | - 'kvm_for_each_memslot' 370 | - 'kvm_for_each_vcpu' 371 | - 'list_for_each' 372 | - 'list_for_each_codec' 373 | - 'list_for_each_codec_safe' 374 | - 'list_for_each_continue' 375 | - 'list_for_each_entry' 376 | - 'list_for_each_entry_continue' 377 | - 'list_for_each_entry_continue_rcu' 378 | - 'list_for_each_entry_continue_reverse' 379 | - 'list_for_each_entry_from' 380 | - 'list_for_each_entry_from_rcu' 381 | - 'list_for_each_entry_from_reverse' 382 | - 'list_for_each_entry_lockless' 383 | - 'list_for_each_entry_rcu' 384 | - 'list_for_each_entry_reverse' 385 | - 'list_for_each_entry_safe' 386 | - 'list_for_each_entry_safe_continue' 387 | - 'list_for_each_entry_safe_from' 388 | - 'list_for_each_entry_safe_reverse' 389 | - 'list_for_each_entry_srcu' 390 | - 'list_for_each_prev' 391 | - 'list_for_each_prev_safe' 392 | - 'list_for_each_safe' 393 | - 'llist_for_each' 394 | - 'llist_for_each_entry' 395 | - 'llist_for_each_entry_safe' 396 | - 'llist_for_each_safe' 397 | - 'mci_for_each_dimm' 398 | - 'media_device_for_each_entity' 399 | - 'media_device_for_each_intf' 400 | - 'media_device_for_each_link' 401 | - 'media_device_for_each_pad' 402 | - 'nanddev_io_for_each_page' 403 | - 'netdev_for_each_lower_dev' 404 | - 'netdev_for_each_lower_private' 405 | - 'netdev_for_each_lower_private_rcu' 406 | - 'netdev_for_each_mc_addr' 407 | - 'netdev_for_each_uc_addr' 408 | - 'netdev_for_each_upper_dev_rcu' 409 | - 'netdev_hw_addr_list_for_each' 410 | - 'nft_rule_for_each_expr' 411 | - 'nla_for_each_attr' 412 | - 'nla_for_each_nested' 413 | - 'nlmsg_for_each_attr' 414 | - 'nlmsg_for_each_msg' 415 | - 'nr_neigh_for_each' 416 | - 'nr_neigh_for_each_safe' 417 | - 'nr_node_for_each' 418 | - 'nr_node_for_each_safe' 419 | - 'of_for_each_phandle' 420 | - 'of_property_for_each_string' 421 | - 'of_property_for_each_u32' 422 | - 'pci_bus_for_each_resource' 423 | - 'pcl_for_each_chunk' 424 | - 'pcl_for_each_segment' 425 | - 'pcm_for_each_format' 426 | - 'ping_portaddr_for_each_entry' 427 | - 'plist_for_each' 428 | - 'plist_for_each_continue' 429 | - 'plist_for_each_entry' 430 | - 'plist_for_each_entry_continue' 431 | - 'plist_for_each_entry_safe' 432 | - 'plist_for_each_safe' 433 | - 'pnp_for_each_card' 434 | - 'pnp_for_each_dev' 435 | - 'protocol_for_each_card' 436 | - 'protocol_for_each_dev' 437 | - 'queue_for_each_hw_ctx' 438 | - 'radix_tree_for_each_slot' 439 | - 'radix_tree_for_each_tagged' 440 | - 'rb_for_each' 441 | - 'rbtree_postorder_for_each_entry_safe' 442 | - 'rdma_for_each_block' 443 | - 'rdma_for_each_port' 444 | - 'rdma_umem_for_each_dma_block' 445 | - 'resource_list_for_each_entry' 446 | - 'resource_list_for_each_entry_safe' 447 | - 'rhl_for_each_entry_rcu' 448 | - 'rhl_for_each_rcu' 449 | - 'rht_for_each' 450 | - 'rht_for_each_entry' 451 | - 'rht_for_each_entry_from' 452 | - 'rht_for_each_entry_rcu' 453 | - 'rht_for_each_entry_rcu_from' 454 | - 'rht_for_each_entry_safe' 455 | - 'rht_for_each_from' 456 | - 'rht_for_each_rcu' 457 | - 'rht_for_each_rcu_from' 458 | - '__rq_for_each_bio' 459 | - 'rq_for_each_bvec' 460 | - 'rq_for_each_segment' 461 | - 'scsi_for_each_prot_sg' 462 | - 'scsi_for_each_sg' 463 | - 'sctp_for_each_hentry' 464 | - 'sctp_skb_for_each' 465 | - 'shdma_for_each_chan' 466 | - '__shost_for_each_device' 467 | - 'shost_for_each_device' 468 | - 'sk_for_each' 469 | - 'sk_for_each_bound' 470 | - 'sk_for_each_entry_offset_rcu' 471 | - 'sk_for_each_from' 472 | - 'sk_for_each_rcu' 473 | - 'sk_for_each_safe' 474 | - 'sk_nulls_for_each' 475 | - 'sk_nulls_for_each_from' 476 | - 'sk_nulls_for_each_rcu' 477 | - 'snd_array_for_each' 478 | - 'snd_pcm_group_for_each_entry' 479 | - 'snd_soc_dapm_widget_for_each_path' 480 | - 'snd_soc_dapm_widget_for_each_path_safe' 481 | - 'snd_soc_dapm_widget_for_each_sink_path' 482 | - 'snd_soc_dapm_widget_for_each_source_path' 483 | - 'tb_property_for_each' 484 | - 'tcf_exts_for_each_action' 485 | - 'udp_portaddr_for_each_entry' 486 | - 'udp_portaddr_for_each_entry_rcu' 487 | - 'usb_hub_for_each_child' 488 | - 'v4l2_device_for_each_subdev' 489 | - 'v4l2_m2m_for_each_dst_buf' 490 | - 'v4l2_m2m_for_each_dst_buf_safe' 491 | - 'v4l2_m2m_for_each_src_buf' 492 | - 'v4l2_m2m_for_each_src_buf_safe' 493 | - 'virtio_device_for_each_vq' 494 | - 'while_for_each_ftrace_op' 495 | - 'xa_for_each' 496 | - 'xa_for_each_marked' 497 | - 'xa_for_each_range' 498 | - 'xa_for_each_start' 499 | - 'xas_for_each' 500 | - 'xas_for_each_conflict' 501 | - 'xas_for_each_marked' 502 | - 'xbc_array_for_each_value' 503 | - 'xbc_for_each_key_value' 504 | - 'xbc_node_for_each_array_value' 505 | - 'xbc_node_for_each_child' 506 | - 'xbc_node_for_each_key_value' 507 | - 'zorro_for_each_dev' 508 | 509 | #IncludeBlocks: Preserve # Unknown to clang-format-5.0 510 | IncludeCategories: 511 | - Regex: '.*' 512 | Priority: 1 513 | IncludeIsMainRegex: '(Test)?$' 514 | IndentCaseLabels: false 515 | #IndentPPDirectives: None # Unknown to clang-format-5.0 516 | IndentWidth: 8 517 | IndentWrappedFunctionNames: false 518 | JavaScriptQuotes: Leave 519 | JavaScriptWrapImports: true 520 | KeepEmptyLinesAtTheStartOfBlocks: false 521 | MacroBlockBegin: '' 522 | MacroBlockEnd: '' 523 | MaxEmptyLinesToKeep: 1 524 | NamespaceIndentation: None 525 | #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 526 | ObjCBlockIndentWidth: 8 527 | ObjCSpaceAfterProperty: true 528 | ObjCSpaceBeforeProtocolList: true 529 | 530 | # Taken from git's rules 531 | #PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 532 | PenaltyBreakBeforeFirstCallParameter: 30 533 | PenaltyBreakComment: 10 534 | PenaltyBreakFirstLessLess: 0 535 | PenaltyBreakString: 10 536 | PenaltyExcessCharacter: 100 537 | PenaltyReturnTypeOnItsOwnLine: 60 538 | 539 | PointerAlignment: Right 540 | ReflowComments: false 541 | SortIncludes: false 542 | #SortUsingDeclarations: false # Unknown to clang-format-4.0 543 | SpaceAfterCStyleCast: false 544 | SpaceAfterTemplateKeyword: true 545 | SpaceBeforeAssignmentOperators: true 546 | #SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 547 | #SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 548 | SpaceBeforeParens: ControlStatements 549 | #SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 550 | SpaceInEmptyParentheses: false 551 | SpacesBeforeTrailingComments: 1 552 | SpacesInAngles: false 553 | SpacesInContainerLiterals: false 554 | SpacesInCStyleCastParentheses: false 555 | SpacesInParentheses: false 556 | SpacesInSquareBrackets: false 557 | Standard: Cpp03 558 | TabWidth: 8 559 | UseTab: Always 560 | ... 561 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | build: 7 | name: build 8 | runs-on: ubuntu-22.04 9 | steps: 10 | - name: checking out 11 | uses: actions/checkout@v3 12 | with: 13 | path: libbpf-async 14 | - name: checking out libbpf 15 | uses: actions/checkout@v3 16 | with: 17 | repository: libbpf/libbpf 18 | path: libbpf 19 | - name: build libbpf 20 | working-directory: libbpf 21 | run: | 22 | sudo apt-get -y install debhelper-compat libelf-dev zlib1g-dev pkg-config 23 | cd src 24 | sudo make install 25 | - name: build 26 | working-directory: libbpf-async 27 | run: | 28 | rustup component add rustfmt --toolchain stable-x86_64-unknown-linux-gnu 29 | rustup component add clippy 30 | cargo clippy -- -D warnings 31 | cargo test --verbose --all 32 | cargo fmt -- --check 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | # BPF build 13 | **/bpf/.output 14 | **/bpf/vmlinux.h 15 | **/*.o 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["libbpf-async", "examples/bashreadline", "examples/profiler"] 4 | -------------------------------------------------------------------------------- /LICENSE-BSD2: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, FUJITA Tomonori 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /LICENSE-LGPL21: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libbpf-async 2 | 3 | A library for writing BPF programs in Async Rust, complementary for [libbpf-rs](https://github.com/libbpf/libbpf-rs), Rust wrapper for [libbpf](https://github.com/libbpf/libbpf). 4 | 5 | Currently, this provides Async-friendly APIs for [BPF ring buffer](https://www.kernel.org/doc/html/latest/bpf/ringbuf.html). 6 | 7 | To use in your project, add into your `Cargo.toml`: 8 | 9 | ```toml 10 | [dependencies] 11 | libbpf-async = "0.2" 12 | ``` 13 | 14 | ## Example 15 | 16 | ```rust,no_run 17 | #[tokio::main] 18 | async fn main() { 19 | let mut builder = TracerSkelBuilder::default(); 20 | let mut skel = builder.open().unwrap().load().unwrap(); 21 | 22 | let mut rb = libbpf_async::RingBuffer::new(skel.obj.map_mut("ringbuf").unwrap()); 23 | loop { 24 | let mut buf = [0; 128]; 25 | let n = rb.read(&mut buf).await.unwrap(); 26 | // do something useful with the buffer 27 | } 28 | } 29 | ``` 30 | 31 | A working example code can be found [here](https://github.com/fujita/libbpf-async/tree/master/examples). 32 | 33 | ## License 34 | 35 | This work is dual-licensed under BSD 2-clause license and GNU LGPL v2.1 license. You can choose between one of them if you use this work. 36 | -------------------------------------------------------------------------------- /examples/bashreadline/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bashreadline" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | object = { version = "0.31.0", features = ["elf"] } 10 | libbpf-rs = "0.22" 11 | plain = "0.2" 12 | chrono = "0.4" 13 | tokio = { version = "1.35", features = ["full"] } 14 | rlimit = "0.9.1" 15 | libbpf-async = { path = "../../libbpf-async" } 16 | 17 | [build-dependencies] 18 | libbpf-cargo = "0.22" 19 | -------------------------------------------------------------------------------- /examples/bashreadline/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::io::Write; 3 | use std::path::PathBuf; 4 | use std::process::Command; 5 | 6 | use libbpf_cargo::SkeletonBuilder; 7 | 8 | const SRC: &str = "src/bpf/bashreadline.bpf.c"; 9 | 10 | fn main() { 11 | let output = Command::new("bpftool") 12 | .arg("btf") 13 | .arg("dump") 14 | .arg("file") 15 | .arg("/sys/kernel/btf/vmlinux") 16 | .arg("format") 17 | .arg("c") 18 | .output() 19 | .unwrap(); 20 | let mut f = std::fs::File::create("./src/bpf/vmlinux.h").unwrap(); 21 | f.write_all(&output.stdout).unwrap(); 22 | 23 | let mut skel = 24 | PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set in build script")); 25 | skel.push("bashreadline.skel.rs"); 26 | SkeletonBuilder::new() 27 | .source(SRC) 28 | .build_and_generate(&skel) 29 | .unwrap(); 30 | println!("cargo:rerun-if-changed={}", SRC); 31 | } 32 | -------------------------------------------------------------------------------- /examples/bashreadline/src/bpf/bashreadline.bpf.c: -------------------------------------------------------------------------------- 1 | #include "vmlinux.h" 2 | #include 3 | #include 4 | 5 | #define TASK_COMM_LEN 256 6 | 7 | struct __attribute__ ((__packed__)) str_t { 8 | u64 pid; 9 | char str[120]; 10 | }; 11 | 12 | /* BPF ringbuf map */ 13 | struct { 14 | __uint(type, BPF_MAP_TYPE_RINGBUF); 15 | __uint(max_entries, 256*1024); 16 | } rb SEC(".maps"); 17 | 18 | SEC("uretprobe/triger_func") 19 | int printret(struct pt_regs *ctx) { 20 | struct str_t data = {}; 21 | char comm[TASK_COMM_LEN] = {}; 22 | u32 pid; 23 | if (!PT_REGS_RC(ctx)) 24 | return 0; 25 | pid = bpf_get_current_pid_tgid() >> 32; 26 | data.pid = pid; 27 | bpf_probe_read_user(&data.str, sizeof(data.str), (void *)PT_REGS_RC(ctx)); 28 | 29 | bpf_get_current_comm(&comm, sizeof(comm)); 30 | if (comm[0] == 'b' && comm[1] == 'a' && comm[2] == 's' && comm[3] == 'h' && comm[4] == 0 ) { 31 | bpf_ringbuf_output(&rb, &data, sizeof(data), 0); 32 | } 33 | 34 | return 0; 35 | }; 36 | 37 | char _license[] SEC("license") = "GPL"; 38 | -------------------------------------------------------------------------------- /examples/bashreadline/src/bpf/trace_helpers.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "trace_helpers.h" 9 | 10 | #define min(x, y) ({ \ 11 | typeof(x) _min1 = (x); \ 12 | typeof(y) _min2 = (y); \ 13 | (void) (&_min1 == &_min2); \ 14 | _min1 < _min2 ? _min1 : _min2; }) 15 | 16 | #define DISK_NAME_LEN 32 17 | 18 | #define MINORBITS 20 19 | #define MINORMASK ((1U << MINORBITS) - 1) 20 | 21 | #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) 22 | 23 | struct ksyms { 24 | struct ksym *syms; 25 | int syms_sz; 26 | int syms_cap; 27 | char *strs; 28 | int strs_sz; 29 | int strs_cap; 30 | }; 31 | 32 | static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned long addr) 33 | { 34 | size_t new_cap, name_len = strlen(name) + 1; 35 | struct ksym *ksym; 36 | void *tmp; 37 | 38 | if (ksyms->strs_sz + name_len > ksyms->strs_cap) { 39 | new_cap = ksyms->strs_cap * 4 / 3; 40 | if (new_cap < ksyms->strs_sz + name_len) 41 | new_cap = ksyms->strs_sz + name_len; 42 | if (new_cap < 1024) 43 | new_cap = 1024; 44 | tmp = realloc(ksyms->strs, new_cap); 45 | if (!tmp) 46 | return -1; 47 | ksyms->strs = tmp; 48 | ksyms->strs_cap = new_cap; 49 | } 50 | if (ksyms->syms_sz + 1 > ksyms->syms_cap) { 51 | new_cap = ksyms->syms_cap * 4 / 3; 52 | if (new_cap < 1024) 53 | new_cap = 1024; 54 | tmp = realloc(ksyms->syms, sizeof(*ksyms->syms) * new_cap); 55 | if (!tmp) 56 | return -1; 57 | ksyms->syms = tmp; 58 | ksyms->syms_cap = new_cap; 59 | } 60 | 61 | ksym = &ksyms->syms[ksyms->syms_sz]; 62 | /* while constructing, re-use pointer as just a plain offset */ 63 | ksym->name = (void *)(unsigned long)ksyms->strs_sz; 64 | ksym->addr = addr; 65 | 66 | memcpy(ksyms->strs + ksyms->strs_sz, name, name_len); 67 | ksyms->strs_sz += name_len; 68 | ksyms->syms_sz++; 69 | 70 | return 0; 71 | } 72 | 73 | static int ksym_cmp(const void *p1, const void *p2) 74 | { 75 | const struct ksym *s1 = p1, *s2 = p2; 76 | 77 | if (s1->addr == s2->addr) 78 | return strcmp(s1->name, s2->name); 79 | return s1->addr < s2->addr ? -1 : 1; 80 | } 81 | 82 | struct ksyms *ksyms__load(void) 83 | { 84 | char sym_type, sym_name[256]; 85 | struct ksyms *ksyms; 86 | unsigned long sym_addr; 87 | int i, ret; 88 | FILE *f; 89 | 90 | f = fopen("/proc/kallsyms", "r"); 91 | if (!f) 92 | return NULL; 93 | 94 | ksyms = calloc(1, sizeof(*ksyms)); 95 | if (!ksyms) 96 | goto err_out; 97 | 98 | while (true) { 99 | ret = fscanf(f, "%lx %c %s%*[^\n]\n", 100 | &sym_addr, &sym_type, sym_name); 101 | if (ret == EOF && feof(f)) 102 | break; 103 | if (ret != 3) 104 | goto err_out; 105 | if (ksyms__add_symbol(ksyms, sym_name, sym_addr)) 106 | goto err_out; 107 | } 108 | 109 | /* now when strings are finalized, adjust pointers properly */ 110 | for (i = 0; i < ksyms->syms_sz; i++) 111 | ksyms->syms[i].name += (unsigned long)ksyms->strs; 112 | 113 | qsort(ksyms->syms, ksyms->syms_sz, sizeof(*ksyms->syms), ksym_cmp); 114 | 115 | fclose(f); 116 | return ksyms; 117 | 118 | err_out: 119 | ksyms__free(ksyms); 120 | fclose(f); 121 | return NULL; 122 | } 123 | 124 | void ksyms__free(struct ksyms *ksyms) 125 | { 126 | if (!ksyms) 127 | return; 128 | 129 | free(ksyms->syms); 130 | free(ksyms->strs); 131 | free(ksyms); 132 | } 133 | 134 | const struct ksym *ksyms__map_addr(const struct ksyms *ksyms, 135 | unsigned long addr) 136 | { 137 | int start = 0, end = ksyms->syms_sz - 1, mid; 138 | unsigned long sym_addr; 139 | 140 | /* find largest sym_addr <= addr using binary search */ 141 | while (start < end) { 142 | mid = start + (end - start + 1) / 2; 143 | sym_addr = ksyms->syms[mid].addr; 144 | 145 | if (sym_addr <= addr) 146 | start = mid; 147 | else 148 | end = mid - 1; 149 | } 150 | 151 | if (start == end && ksyms->syms[start].addr <= addr) 152 | return &ksyms->syms[start]; 153 | return NULL; 154 | } 155 | 156 | const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms, 157 | const char *name) 158 | { 159 | int i; 160 | 161 | for (i = 0; i < ksyms->syms_sz; i++) { 162 | if (strcmp(ksyms->syms[i].name, name) == 0) 163 | return &ksyms->syms[i]; 164 | } 165 | 166 | return NULL; 167 | } 168 | 169 | struct partitions { 170 | struct partition *items; 171 | int sz; 172 | }; 173 | 174 | static int partitions__add_partition(struct partitions *partitions, 175 | const char *name, unsigned int dev) 176 | { 177 | struct partition *partition; 178 | void *tmp; 179 | 180 | tmp = realloc(partitions->items, (partitions->sz + 1) * 181 | sizeof(*partitions->items)); 182 | if (!tmp) 183 | return -1; 184 | partitions->items = tmp; 185 | partition = &partitions->items[partitions->sz]; 186 | partition->name = strdup(name); 187 | partition->dev = dev; 188 | partitions->sz++; 189 | 190 | return 0; 191 | } 192 | 193 | struct partitions *partitions__load(void) 194 | { 195 | char part_name[DISK_NAME_LEN]; 196 | unsigned int devmaj, devmin; 197 | unsigned long long nop; 198 | struct partitions *partitions; 199 | char buf[64]; 200 | FILE *f; 201 | 202 | f = fopen("/proc/partitions", "r"); 203 | if (!f) 204 | return NULL; 205 | 206 | partitions = calloc(1, sizeof(*partitions)); 207 | if (!partitions) 208 | goto err_out; 209 | 210 | while (fgets(buf, sizeof(buf), f) != NULL) { 211 | /* skip heading */ 212 | if (buf[0] != ' ' || buf[0] == '\n') 213 | continue; 214 | if (sscanf(buf, "%u %u %llu %s", &devmaj, &devmin, &nop, 215 | part_name) != 4) 216 | goto err_out; 217 | if (partitions__add_partition(partitions, part_name, 218 | MKDEV(devmaj, devmin))) 219 | goto err_out; 220 | } 221 | 222 | fclose(f); 223 | return partitions; 224 | 225 | err_out: 226 | partitions__free(partitions); 227 | fclose(f); 228 | return NULL; 229 | } 230 | 231 | void partitions__free(struct partitions *partitions) 232 | { 233 | int i; 234 | 235 | if (!partitions) 236 | return; 237 | 238 | for (i = 0; i < partitions->sz; i++) 239 | free(partitions->items[i].name); 240 | free(partitions->items); 241 | free(partitions); 242 | } 243 | 244 | const struct partition * 245 | partitions__get_by_dev(const struct partitions *partitions, unsigned int dev) 246 | { 247 | int i; 248 | 249 | for (i = 0; i < partitions->sz; i++) { 250 | if (partitions->items[i].dev == dev) 251 | return &partitions->items[i]; 252 | } 253 | 254 | return NULL; 255 | } 256 | 257 | const struct partition * 258 | partitions__get_by_name(const struct partitions *partitions, const char *name) 259 | { 260 | int i; 261 | 262 | for (i = 0; i < partitions->sz; i++) { 263 | if (strcmp(partitions->items[i].name, name) == 0) 264 | return &partitions->items[i]; 265 | } 266 | 267 | return NULL; 268 | } 269 | 270 | static void print_stars(unsigned int val, unsigned int val_max, int width) 271 | { 272 | int num_stars, num_spaces, i; 273 | bool need_plus; 274 | 275 | num_stars = min(val, val_max) * width / val_max; 276 | num_spaces = width - num_stars; 277 | need_plus = val > val_max; 278 | 279 | for (i = 0; i < num_stars; i++) 280 | printf("*"); 281 | for (i = 0; i < num_spaces; i++) 282 | printf(" "); 283 | if (need_plus) 284 | printf("+"); 285 | } 286 | 287 | void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type) 288 | { 289 | int stars_max = 40, idx_max = -1; 290 | unsigned int val, val_max = 0; 291 | unsigned long long low, high; 292 | int stars, width, i; 293 | 294 | for (i = 0; i < vals_size; i++) { 295 | val = vals[i]; 296 | if (val > 0) 297 | idx_max = i; 298 | if (val > val_max) 299 | val_max = val; 300 | } 301 | 302 | if (idx_max < 0) 303 | return; 304 | 305 | printf("%*s%-*s : count distribution\n", idx_max <= 32 ? 5 : 15, "", 306 | idx_max <= 32 ? 19 : 29, val_type); 307 | 308 | if (idx_max <= 32) 309 | stars = stars_max; 310 | else 311 | stars = stars_max / 2; 312 | 313 | for (i = 0; i <= idx_max; i++) { 314 | low = (1ULL << (i + 1)) >> 1; 315 | high = (1ULL << (i + 1)) - 1; 316 | if (low == high) 317 | low -= 1; 318 | val = vals[i]; 319 | width = idx_max <= 32 ? 10 : 20; 320 | printf("%*lld -> %-*lld : %-8d |", width, low, width, high, val); 321 | print_stars(val, val_max, stars); 322 | printf("|\n"); 323 | } 324 | } 325 | 326 | void print_linear_hist(unsigned int *vals, int vals_size, const char *val_type) 327 | { 328 | int i, stars_max = 40, idx_max = -1; 329 | unsigned int val, val_max = 0; 330 | 331 | for (i = 0; i < vals_size; i++) { 332 | val = vals[i]; 333 | if (val > 0) 334 | idx_max = i; 335 | if (val > val_max) 336 | val_max = val; 337 | } 338 | 339 | if (idx_max < 0) 340 | return; 341 | 342 | printf(" %-13s : count distribution\n", val_type); 343 | for (i = 0; i <= idx_max; i++) { 344 | val = vals[i]; 345 | printf(" %-10d : %-8d |", i, val); 346 | print_stars(val, val_max, stars_max); 347 | printf("|\n"); 348 | } 349 | } 350 | 351 | unsigned long long get_ktime_ns(void) 352 | { 353 | struct timespec ts; 354 | 355 | clock_gettime(CLOCK_MONOTONIC, &ts); 356 | return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; 357 | } 358 | 359 | int bump_memlock_rlimit(void) 360 | { 361 | struct rlimit rlim_new = { 362 | .rlim_cur = RLIM_INFINITY, 363 | .rlim_max = RLIM_INFINITY, 364 | }; 365 | 366 | return setrlimit(RLIMIT_MEMLOCK, &rlim_new); 367 | } 368 | -------------------------------------------------------------------------------- /examples/bashreadline/src/bpf/trace_helpers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2 | #ifndef __TRACE_HELPERS_H 3 | #define __TRACE_HELPERS_H 4 | 5 | #define NSEC_PER_SEC 1000000000ULL 6 | 7 | struct ksym { 8 | const char *name; 9 | unsigned long addr; 10 | }; 11 | 12 | struct ksyms; 13 | 14 | struct ksyms *ksyms__load(void); 15 | void ksyms__free(struct ksyms *ksyms); 16 | const struct ksym *ksyms__map_addr(const struct ksyms *ksyms, 17 | unsigned long addr); 18 | const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms, 19 | const char *name); 20 | 21 | struct partition { 22 | char *name; 23 | unsigned int dev; 24 | }; 25 | 26 | struct partitions; 27 | 28 | struct partitions *partitions__load(void); 29 | void partitions__free(struct partitions *partitions); 30 | const struct partition * 31 | partitions__get_by_dev(const struct partitions *partitions, unsigned int dev); 32 | const struct partition * 33 | partitions__get_by_name(const struct partitions *partitions, const char *name); 34 | 35 | void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type); 36 | void print_linear_hist(unsigned int *vals, int vals_size, const char *val_type); 37 | 38 | unsigned long long get_ktime_ns(void); 39 | int bump_memlock_rlimit(void); 40 | 41 | #endif /* __TRACE_HELPERS_H */ 42 | -------------------------------------------------------------------------------- /examples/bashreadline/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 and 2022 The libbpf-async Authors. 2 | // 3 | // Licensed under LGPL-2.1 or BSD-2-Clause. 4 | 5 | use chrono::prelude::*; 6 | use libbpf_rs::skel::{OpenSkel, SkelBuilder}; 7 | use object::{Object, ObjectSymbol}; 8 | use plain::Plain; 9 | use std::fs; 10 | use tokio::io::AsyncReadExt; 11 | 12 | mod bashreadline { 13 | include!(concat!(env!("OUT_DIR"), "/bashreadline.skel.rs")); 14 | } 15 | use bashreadline::*; 16 | 17 | const BINARY_NAME: &str = "/bin/bash"; 18 | const SYM_NAME: &str = "readline"; 19 | const RINGBUF_NAME: &str = "rb"; 20 | 21 | #[repr(C)] 22 | #[derive(Copy, Clone)] 23 | struct Entry { 24 | pub pid: u64, 25 | pub str: [u8; 120], 26 | } 27 | 28 | unsafe impl Plain for Entry {} 29 | 30 | impl Entry { 31 | fn copy_from_bytes(buf: &[u8]) -> Entry { 32 | let mut e = Entry { 33 | pid: 0, 34 | str: [0; 120], 35 | }; 36 | e.copy_from_bytes(buf).expect("buffer is short"); 37 | e 38 | } 39 | } 40 | 41 | #[tokio::main] 42 | async fn main() { 43 | rlimit::setrlimit( 44 | rlimit::Resource::MEMLOCK, 45 | rlimit::INFINITY, 46 | rlimit::INFINITY, 47 | ) 48 | .unwrap(); 49 | 50 | let mut builder = BashreadlineSkelBuilder::default(); 51 | builder.obj_builder.debug(true); 52 | let mut skel = builder.open().unwrap().load().unwrap(); 53 | 54 | let bin_data = fs::read(BINARY_NAME).unwrap(); 55 | let obj_file = object::File::parse(&*bin_data).unwrap(); 56 | let mut offset = 0; 57 | for s in obj_file.dynamic_symbols() { 58 | if s.name().unwrap() == SYM_NAME { 59 | offset = s.address(); 60 | } 61 | } 62 | assert_ne!(offset, 0); 63 | 64 | let _link = skel 65 | .obj 66 | .prog_mut("printret") 67 | .unwrap() 68 | .attach_uprobe(true, -1, BINARY_NAME, offset as usize) 69 | .unwrap(); 70 | 71 | let mut rb = libbpf_async::RingBuffer::new(skel.obj.map(RINGBUF_NAME).unwrap()); 72 | println!("TIME PID COMMAND"); 73 | loop { 74 | let mut buf = [0; 128]; 75 | let n = rb.read(&mut buf).await.unwrap(); 76 | let e = Entry::copy_from_bytes(&buf[0..n]); 77 | let mut s: Vec = e.str.iter().take_while(|x| **x != 0).cloned().collect(); 78 | s.push(0); 79 | 80 | let local: DateTime = Local::now(); 81 | println!( 82 | "{:0>2}:{}:{} {:>6} {}", 83 | local.hour(), 84 | local.minute(), 85 | local.second(), 86 | e.pid, 87 | String::from_utf8(s).unwrap() 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/profiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "profiler" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | addr2line = "0.17.0" 10 | chrono = "0.4" 11 | clap = { version = "4.2.7", features = ["derive"] } 12 | libbpf-rs = "0.22" 13 | nix = "0.26.2" 14 | num_cpus = "1.0" 15 | perf-event-open-sys = "4.0.0" 16 | plain = "0.2" 17 | rlimit = "0.9.1" 18 | tokio = { version = "1.35", features = ["full"] } 19 | libbpf-async = { path = "../../libbpf-async" } 20 | 21 | [build-dependencies] 22 | libbpf-cargo = "0.22" 23 | -------------------------------------------------------------------------------- /examples/profiler/README.md: -------------------------------------------------------------------------------- 1 | # BFP profiler 2 | 3 | The BPF code sends the results of `bpf_get_stack()` to user space via BPF ring buffer. The user space code converts the instruction pointers to human-readable function names. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | $ ./target/debug/profiler --help 9 | profiler 0.1.0 10 | 11 | USAGE: 12 | profiler [OPTIONS] 13 | 14 | ARGS: 15 | 16 | 17 | OPTIONS: 18 | --debug debug bpf 19 | -h, --help Print help information 20 | -V, --version Print version information 21 | ``` 22 | 23 | ```bash 24 | # sudo ./target/debug/profiler ~/git/foo/target/debug/foo 25 | 353885 2022-04-13 00:24:57.416099734 UTC 26 | 55f6a6137734 compiler_builtins::int::specialized_div_rem::u128_div_rem 27 | 55f6a610233e fib::exec 28 | 55f6a610225f fib::main 29 | 55f6a6102f2e core::ops::function::FnOnce::call_once 30 | 55f6a6101f01 std::sys_common::backtrace::__rust_begin_short_backtrace 31 | 55f6a6101e54 std::rt::lang_start::{{closure}} 32 | 55f6a6116501 std::rt::lang_start_internal 33 | 34 | 353885 2022-04-13 00:24:57.426197765 UTC 35 | 55f6a6137613 __divti3 36 | 55f6a610233e fib::exec 37 | 55f6a610225f fib::main 38 | 55f6a6102f2e core::ops::function::FnOnce::call_once 39 | 55f6a6101f01 std::sys_common::backtrace::__rust_begin_short_backtrace 40 | 55f6a6101e54 std::rt::lang_start::{{closure}} 41 | 55f6a6116501 std::rt::lang_start_internal 42 | ``` 43 | 44 | ## Caveat 45 | 46 | `bpf_get_stack()` needs frame pointers. You need to compile a binary with the following option: 47 | 48 | ```bash 49 | RUSTFLAGS=-Cforce-frame-pointers=yes cargo build 50 | ``` 51 | -------------------------------------------------------------------------------- /examples/profiler/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::io::Write; 3 | use std::path::PathBuf; 4 | use std::process::Command; 5 | 6 | use libbpf_cargo::SkeletonBuilder; 7 | 8 | const SRC: &str = "src/bpf/profiler.bpf.c"; 9 | 10 | fn main() { 11 | let output = Command::new("bpftool") 12 | .arg("btf") 13 | .arg("dump") 14 | .arg("file") 15 | .arg("/sys/kernel/btf/vmlinux") 16 | .arg("format") 17 | .arg("c") 18 | .output() 19 | .unwrap(); 20 | let mut f = std::fs::File::create("./src/bpf/vmlinux.h").unwrap(); 21 | f.write_all(&output.stdout).unwrap(); 22 | 23 | let mut skel = 24 | PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set in build script")); 25 | skel.push("profiler.skel.rs"); 26 | SkeletonBuilder::new() 27 | .source(SRC) 28 | .build_and_generate(&skel) 29 | .unwrap(); 30 | println!("cargo:rerun-if-changed={}", SRC); 31 | } 32 | -------------------------------------------------------------------------------- /examples/profiler/src/bpf/profiler.bpf.c: -------------------------------------------------------------------------------- 1 | #include "vmlinux.h" 2 | #include 3 | 4 | #define MAX_FRAMES 32 5 | 6 | struct __attribute__((__packed__)) Stack { 7 | u64 ip[MAX_FRAMES]; 8 | }; 9 | 10 | struct { 11 | __uint(type, BPF_MAP_TYPE_HASH); 12 | __uint(max_entries, 1); 13 | __type(key, __u32); 14 | __type(value, __u32); 15 | } hmap SEC(".maps"); 16 | 17 | /* BPF ringbuf map */ 18 | struct { 19 | __uint(type, BPF_MAP_TYPE_RINGBUF); 20 | __uint(max_entries, 512 * 4096); 21 | } rb SEC(".maps"); 22 | 23 | SEC("perf_event") 24 | int do_perf_event(struct bpf_perf_event_data *ctx) 25 | { 26 | int ret; 27 | struct Stack *stack; 28 | 29 | u32 tgid = bpf_get_current_pid_tgid() >> 32; 30 | 31 | if (!bpf_map_lookup_elem(&hmap, &tgid)) { 32 | return 0; 33 | } 34 | 35 | stack = bpf_ringbuf_reserve(&rb, sizeof(*stack), 0); 36 | if (!stack) { 37 | return 0; 38 | } 39 | 40 | ret = bpf_get_stack(ctx, (void *)stack->ip, 8 * MAX_FRAMES, 41 | BPF_F_USER_STACK); 42 | if (ret <= 0) { 43 | bpf_ringbuf_discard(stack, 0); 44 | return 0; 45 | } 46 | bpf_ringbuf_submit(stack, 0); 47 | return 0; 48 | } 49 | 50 | char _license[] SEC("license") = "GPL"; 51 | -------------------------------------------------------------------------------- /examples/profiler/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 and 2022 The libbpf-async Authors. 2 | // 3 | // Licensed under LGPL-2.1 or BSD-2-Clause. 4 | 5 | use chrono::Utc; 6 | use clap::Parser; 7 | use libbpf_rs::skel::{OpenSkel, SkelBuilder}; 8 | use perf_event_open_sys as sys; 9 | use plain::Plain; 10 | use std::collections::HashMap; 11 | use std::fs::{self, File}; 12 | use std::io::{BufRead, BufReader}; 13 | use std::os::fd::{AsFd, AsRawFd}; 14 | use std::process::Command; 15 | use std::u64; 16 | 17 | mod profiler { 18 | include!(concat!(env!("OUT_DIR"), "/profiler.skel.rs")); 19 | } 20 | use profiler::*; 21 | 22 | const RINGBUF_NAME: &str = "rb"; 23 | const MAX_FRAME: usize = 32; 24 | 25 | #[repr(C)] 26 | #[derive(Copy, Clone, Default)] 27 | struct Stack { 28 | pub ip: [u64; MAX_FRAME], 29 | } 30 | 31 | unsafe impl Plain for Stack {} 32 | 33 | impl Stack { 34 | fn copy_from_bytes(buf: &[u8]) -> Stack { 35 | let mut e = Stack::default(); 36 | e.copy_from_bytes(buf).expect("buffer is short"); 37 | e 38 | } 39 | } 40 | 41 | struct Area { 42 | start: u64, 43 | end: u64, 44 | ctx: addr2line::Context, 45 | } 46 | 47 | const PERF_EVENT_IOC_MAGIC: u8 = b'$'; 48 | const PERF_EVENT_IOC_SET_BPF: u8 = 8; 49 | nix::ioctl_write_int!( 50 | perf_event_set_bpf, 51 | PERF_EVENT_IOC_MAGIC, 52 | PERF_EVENT_IOC_SET_BPF 53 | ); 54 | 55 | const PERF_EVENT_IOC_ENABLE: u8 = 0; 56 | nix::ioctl_none!( 57 | perf_event_enable, 58 | PERF_EVENT_IOC_MAGIC, 59 | PERF_EVENT_IOC_ENABLE 60 | ); 61 | 62 | #[derive(Parser, Debug)] 63 | #[clap(author, version, about, long_about = None)] 64 | struct Args { 65 | command: String, 66 | 67 | /// debug bpf 68 | #[clap(long)] 69 | debug: bool, 70 | } 71 | 72 | fn addr2func(range: &[Area], addr: u64) -> String { 73 | let idx = match range.binary_search_by_key(&addr, |x| x.start) { 74 | Ok(i) => i, 75 | Err(i) => { 76 | if i == 0 { 77 | return "".to_string(); 78 | } 79 | i - 1 80 | } 81 | }; 82 | let area = &range[idx]; 83 | if area.end < addr { 84 | return "".to_string(); 85 | } 86 | 87 | if let Ok(mut frames) = area.ctx.find_frames(addr - area.start) { 88 | let mut func_name = "".to_string(); 89 | while let Ok(Some(f)) = frames.next() { 90 | if let Some(name) = f.function { 91 | func_name = format!("{}", name.demangle().unwrap()); 92 | } 93 | } 94 | func_name 95 | } else { 96 | format!("\"\" {:x}", addr - area.start) 97 | } 98 | } 99 | 100 | fn main() { 101 | let args = Args::parse(); 102 | 103 | rlimit::setrlimit( 104 | rlimit::Resource::MEMLOCK, 105 | rlimit::INFINITY, 106 | rlimit::INFINITY, 107 | ) 108 | .unwrap(); 109 | 110 | let mut builder = ProfilerSkelBuilder::default(); 111 | if args.debug { 112 | builder.obj_builder.debug(true); 113 | } 114 | let mut skel = builder.open().unwrap().load().unwrap(); 115 | let prog_fd = skel.obj.prog("do_perf_event").unwrap().as_fd().as_raw_fd(); 116 | let hmap = skel.obj.map_mut("hmap").unwrap(); 117 | 118 | for cpu in 0..num_cpus::get() { 119 | let mut attrs = sys::bindings::perf_event_attr { 120 | size: std::mem::size_of::() as u32, 121 | type_: sys::bindings::PERF_TYPE_SOFTWARE, 122 | config: sys::bindings::PERF_COUNT_SW_CPU_CLOCK as u64, 123 | __bindgen_anon_1: sys::bindings::perf_event_attr__bindgen_ty_1 { sample_freq: 99 }, 124 | ..Default::default() 125 | }; 126 | attrs.set_freq(1); 127 | let event_fd = unsafe { 128 | sys::perf_event_open( 129 | &mut attrs, 130 | -1, 131 | cpu as i32, 132 | -1, 133 | sys::bindings::PERF_FLAG_FD_CLOEXEC as u64, 134 | ) 135 | }; 136 | if event_fd < 0 { 137 | panic!("perf_event_open failed {}", event_fd); 138 | } 139 | 140 | unsafe { 141 | if let Err(ret) = perf_event_set_bpf(event_fd, prog_fd as u64) { 142 | panic!("{:?}", ret); 143 | } 144 | } 145 | unsafe { 146 | if let Err(ret) = perf_event_enable(event_fd) { 147 | panic!("{:?}", ret); 148 | } 149 | } 150 | } 151 | 152 | let child = Command::new(args.command) 153 | .spawn() 154 | .expect("failed to execute"); 155 | let pid = child.id(); 156 | 157 | let mut memmaps: HashMap> = HashMap::default(); 158 | let reader = 159 | BufReader::new(File::open(format!("/proc/{}/maps", pid)).expect("failed to open maps")); 160 | for line in reader.lines() { 161 | if let Ok(line) = line { 162 | let v: Vec<&str> = line.split_ascii_whitespace().collect(); 163 | if v.len() != 6 { 164 | continue; 165 | } 166 | let object = v[5].to_string(); 167 | if object.starts_with('[') { 168 | continue; 169 | } 170 | let entry = memmaps.entry(object).or_default(); 171 | let range: Vec<&str> = v[0].split('-').collect(); 172 | let start = u64::from_str_radix(range[0], 16).unwrap(); 173 | let end = u64::from_str_radix(range[1], 16).unwrap(); 174 | entry.push((start, end)); 175 | } else { 176 | break; 177 | } 178 | } 179 | 180 | let mut range = Vec::new(); 181 | for (obj, r) in memmaps { 182 | let bin_data = fs::read(obj).expect("failed to read"); 183 | 184 | if let Ok(ctx) = addr2line::Context::new( 185 | &addr2line::object::read::File::parse(&*bin_data).expect("failed to parse elf"), 186 | ) { 187 | range.push(Area { 188 | start: r[0].0, 189 | end: r[r.len() - 1].1, 190 | ctx, 191 | }); 192 | } 193 | } 194 | 195 | range.sort_by_key(|x| x.start); 196 | 197 | let rt = tokio::runtime::Builder::new_multi_thread() 198 | .enable_all() 199 | .build() 200 | .unwrap(); 201 | 202 | hmap.update( 203 | &pid.to_ne_bytes(), 204 | &pid.to_ne_bytes(), 205 | libbpf_rs::MapFlags::ANY, 206 | ) 207 | .expect("failed to update pid map"); 208 | 209 | rt.block_on(async move { 210 | use tokio::io::AsyncReadExt; 211 | 212 | let mut rb = libbpf_async::RingBuffer::new(skel.obj.map(RINGBUF_NAME).unwrap()); 213 | loop { 214 | let mut buf = [0; std::mem::size_of::()]; 215 | let n = rb.read(&mut buf).await.unwrap(); 216 | let e = Stack::copy_from_bytes(&buf[0..n]); 217 | println!("{} {}", pid, Utc::now()); 218 | for i in 0..MAX_FRAME { 219 | if e.ip[i] == 0 { 220 | break; 221 | } 222 | println!("{:x} {}", e.ip[i], addr2func(&range, e.ip[i])); 223 | } 224 | println!(); 225 | } 226 | }); 227 | } 228 | -------------------------------------------------------------------------------- /libbpf-async/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libbpf-async" 3 | version = "0.2.0" 4 | edition = "2021" 5 | description = "library for writing BPF programs in Async Rust, complementary for libbpf-rs" 6 | license = "LGPL-2.1 OR BSD-2-Clause" 7 | repository = "https://github.com/fujita/libbpf-async" 8 | homepage = "https://github.com/fujita/libbpf-async" 9 | readme = "../README.md" 10 | keywords = ["bpf", "libbpf", "async"] 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | libbpf-rs = "0.22" 16 | nix = "0.26.2" 17 | tokio = { version = "1.35", features = ["full"] } 18 | page_size = "0.5.0" 19 | futures = "0.3" 20 | -------------------------------------------------------------------------------- /libbpf-async/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod ringbuf; 2 | pub use ringbuf::RingBuffer; 3 | -------------------------------------------------------------------------------- /libbpf-async/src/ringbuf.rs: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2021 and 2022 The libbpf-async Authors. 2 | // 3 | // Licensed under LGPL-2.1 or BSD-2-Clause. 4 | 5 | use core::task::{Context, Poll}; 6 | use libbpf_rs::{query::MapInfoIter, Map}; 7 | use std::io::Result; 8 | use std::num::NonZeroUsize; 9 | use std::os::fd::{AsFd, AsRawFd, RawFd}; 10 | use tokio::io::unix::AsyncFd; 11 | use tokio::io::{AsyncRead, ReadBuf}; 12 | 13 | const BPF_RINGBUF_BUSY_BIT: u32 = 1 << 31; 14 | const BPF_RINGBUF_DISCARD_BIT: u32 = 1 << 30; 15 | const BPF_RINGBUF_HDR_SZ: u32 = 8; 16 | 17 | pub struct RingBuffer { 18 | mask: u64, 19 | async_fd: AsyncFd, 20 | consumer: *mut core::ffi::c_void, 21 | producer: *mut core::ffi::c_void, 22 | data: *mut core::ffi::c_void, 23 | } 24 | 25 | impl RingBuffer { 26 | pub fn new(map: &Map) -> Self { 27 | let mut max_entries = 0; 28 | for m in MapInfoIter::default() { 29 | if let Ok(name) = m.name.to_str() { 30 | if name == map.name() { 31 | max_entries = m.max_entries; 32 | } 33 | } 34 | } 35 | let psize = page_size::get(); 36 | let fd = map.as_fd().as_raw_fd(); 37 | let consumer = unsafe { 38 | nix::sys::mman::mmap( 39 | None, 40 | NonZeroUsize::new(psize).expect("page size must not be zero"), 41 | nix::sys::mman::ProtFlags::PROT_WRITE | nix::sys::mman::ProtFlags::PROT_READ, 42 | nix::sys::mman::MapFlags::MAP_SHARED, 43 | fd, 44 | 0, 45 | ) 46 | .unwrap() 47 | }; 48 | let producer = unsafe { 49 | nix::sys::mman::mmap( 50 | None, 51 | NonZeroUsize::new(psize + 2 * max_entries as usize) 52 | .expect("page size + 2 * max_entries must not be zero"), 53 | nix::sys::mman::ProtFlags::PROT_READ, 54 | nix::sys::mman::MapFlags::MAP_SHARED, 55 | fd, 56 | psize as i64, 57 | ) 58 | .unwrap() 59 | }; 60 | 61 | RingBuffer { 62 | mask: (max_entries - 1) as u64, 63 | async_fd: AsyncFd::with_interest(fd, tokio::io::Interest::READABLE).unwrap(), 64 | consumer, 65 | producer, 66 | data: unsafe { producer.add(psize) }, 67 | } 68 | } 69 | 70 | fn roundup_len(mut len: u32) -> u32 { 71 | len <<= 2; 72 | len >>= 2; 73 | len += BPF_RINGBUF_HDR_SZ; 74 | (len + 7) / 8 * 8 75 | } 76 | } 77 | 78 | impl Drop for RingBuffer { 79 | fn drop(&mut self) { 80 | let psize = page_size::get(); 81 | unsafe { 82 | let _ = nix::sys::mman::munmap(self.consumer, psize); 83 | let _ = nix::sys::mman::munmap(self.producer, psize + 2 * (self.mask as usize + 1)); 84 | } 85 | } 86 | } 87 | 88 | impl AsyncRead for RingBuffer { 89 | fn poll_read( 90 | self: core::pin::Pin<&mut Self>, 91 | cx: &mut Context<'_>, 92 | buf: &mut ReadBuf<'_>, 93 | ) -> Poll> { 94 | loop { 95 | let mut cons_pos = 96 | unsafe { std::ptr::read_volatile(self.consumer as *const std::os::raw::c_ulong) }; 97 | std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst); 98 | let prod_pos = 99 | unsafe { std::ptr::read_volatile(self.producer as *const std::os::raw::c_ulong) }; 100 | std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst); 101 | if cons_pos < prod_pos { 102 | let len_ptr = unsafe { self.data.offset((cons_pos & self.mask) as isize) }; 103 | let mut len = unsafe { std::ptr::read_volatile(len_ptr as *const u32) }; 104 | std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst); 105 | 106 | if (len & BPF_RINGBUF_BUSY_BIT) == 0 { 107 | cons_pos += RingBuffer::roundup_len(len) as u64; 108 | if (len & BPF_RINGBUF_DISCARD_BIT) == 0 { 109 | let sample = unsafe { 110 | std::slice::from_raw_parts_mut( 111 | len_ptr.offset(BPF_RINGBUF_HDR_SZ as isize) as *mut u8, 112 | len as usize, 113 | ) 114 | }; 115 | len = std::cmp::min(len, buf.capacity() as u32); 116 | buf.put_slice(&sample[..len as usize]); 117 | } 118 | std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst); 119 | unsafe { 120 | std::ptr::write_volatile( 121 | self.consumer as *mut std::os::raw::c_ulong, 122 | cons_pos, 123 | ) 124 | }; 125 | if (len & BPF_RINGBUF_DISCARD_BIT) == 0 { 126 | return Poll::Ready(Ok(())); 127 | } else { 128 | continue; 129 | } 130 | } 131 | } 132 | let mut ev = futures::ready!(self.async_fd.poll_read_ready(cx))?; 133 | ev.clear_ready(); 134 | } 135 | } 136 | } 137 | --------------------------------------------------------------------------------