mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2025-12-31 21:06:25 +00:00
398 lines
41 KiB
Plaintext
398 lines
41 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "22dd4e7b-2ea2-49cb-a8d5-1da108c10034",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import time\n",
|
|
"\n",
|
|
"from pythonbpf import bpf, map, section, bpfglobal, BPF\n",
|
|
"from pythonbpf.helper import pid\n",
|
|
"from pythonbpf.maps import HashMap\n",
|
|
"from pylibbpf import BpfMap\n",
|
|
"from ctypes import c_void_p, c_int64, c_uint64, c_int32\n",
|
|
"import matplotlib.pyplot as plt"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "ac7a07bf-440f-41e2-bec8-95f520f9cd53",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Module(\n",
|
|
" body=[\n",
|
|
" FunctionDef(\n",
|
|
" name='hist',\n",
|
|
" args=arguments(\n",
|
|
" posonlyargs=[],\n",
|
|
" args=[],\n",
|
|
" kwonlyargs=[],\n",
|
|
" kw_defaults=[],\n",
|
|
" defaults=[]),\n",
|
|
" body=[\n",
|
|
" Return(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='HashMap', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[\n",
|
|
" keyword(\n",
|
|
" arg='key',\n",
|
|
" value=Name(id='c_int32', ctx=Load())),\n",
|
|
" keyword(\n",
|
|
" arg='value',\n",
|
|
" value=Name(id='c_uint64', ctx=Load())),\n",
|
|
" keyword(\n",
|
|
" arg='max_entries',\n",
|
|
" value=Constant(value=4096))]))],\n",
|
|
" decorator_list=[\n",
|
|
" Name(id='bpf', ctx=Load()),\n",
|
|
" Name(id='map', ctx=Load())],\n",
|
|
" returns=Name(id='HashMap', ctx=Load()),\n",
|
|
" type_params=[]),\n",
|
|
" FunctionDef(\n",
|
|
" name='hello',\n",
|
|
" args=arguments(\n",
|
|
" posonlyargs=[],\n",
|
|
" args=[\n",
|
|
" arg(\n",
|
|
" arg='ctx',\n",
|
|
" annotation=Name(id='c_void_p', ctx=Load()))],\n",
|
|
" kwonlyargs=[],\n",
|
|
" kw_defaults=[],\n",
|
|
" defaults=[]),\n",
|
|
" body=[\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='process_id', ctx=Store())],\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='pid', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[])),\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='one', ctx=Store())],\n",
|
|
" value=Constant(value=1)),\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='prev', ctx=Store())],\n",
|
|
" value=Call(\n",
|
|
" func=Attribute(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='hist', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]),\n",
|
|
" attr='lookup',\n",
|
|
" ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Name(id='process_id', ctx=Load())],\n",
|
|
" keywords=[])),\n",
|
|
" If(\n",
|
|
" test=Name(id='prev', ctx=Load()),\n",
|
|
" body=[\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='previous_value', ctx=Store())],\n",
|
|
" value=BinOp(\n",
|
|
" left=Name(id='prev', ctx=Load()),\n",
|
|
" op=Add(),\n",
|
|
" right=Constant(value=1))),\n",
|
|
" Expr(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='print', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" JoinedStr(\n",
|
|
" values=[\n",
|
|
" Constant(value='count: '),\n",
|
|
" FormattedValue(\n",
|
|
" value=Name(id='previous_value', ctx=Load()),\n",
|
|
" conversion=-1),\n",
|
|
" Constant(value=' with '),\n",
|
|
" FormattedValue(\n",
|
|
" value=Name(id='process_id', ctx=Load()),\n",
|
|
" conversion=-1)])],\n",
|
|
" keywords=[])),\n",
|
|
" Expr(\n",
|
|
" value=Call(\n",
|
|
" func=Attribute(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='hist', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]),\n",
|
|
" attr='update',\n",
|
|
" ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Name(id='process_id', ctx=Load()),\n",
|
|
" Name(id='previous_value', ctx=Load())],\n",
|
|
" keywords=[])),\n",
|
|
" Return(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='c_int64', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Constant(value=0)],\n",
|
|
" keywords=[]))],\n",
|
|
" orelse=[\n",
|
|
" Expr(\n",
|
|
" value=Call(\n",
|
|
" func=Attribute(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='hist', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]),\n",
|
|
" attr='update',\n",
|
|
" ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Name(id='process_id', ctx=Load()),\n",
|
|
" Name(id='one', ctx=Load())],\n",
|
|
" keywords=[]))]),\n",
|
|
" Return(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='c_int64', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Constant(value=0)],\n",
|
|
" keywords=[]))],\n",
|
|
" decorator_list=[\n",
|
|
" Name(id='bpf', ctx=Load()),\n",
|
|
" Call(\n",
|
|
" func=Name(id='section', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Constant(value='tracepoint/syscalls/sys_enter_clone')],\n",
|
|
" keywords=[])],\n",
|
|
" returns=Name(id='c_int64', ctx=Load()),\n",
|
|
" type_params=[]),\n",
|
|
" FunctionDef(\n",
|
|
" name='LICENSE',\n",
|
|
" args=arguments(\n",
|
|
" posonlyargs=[],\n",
|
|
" args=[],\n",
|
|
" kwonlyargs=[],\n",
|
|
" kw_defaults=[],\n",
|
|
" defaults=[]),\n",
|
|
" body=[\n",
|
|
" Return(\n",
|
|
" value=Constant(value='GPL'))],\n",
|
|
" decorator_list=[\n",
|
|
" Name(id='bpf', ctx=Load()),\n",
|
|
" Name(id='bpfglobal', ctx=Load())],\n",
|
|
" returns=Name(id='str', ctx=Load()),\n",
|
|
" type_params=[]),\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='b', ctx=Store())],\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='BPF', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]))],\n",
|
|
" type_ignores=[])\n",
|
|
"Found BPF function/struct: hist\n",
|
|
"Found BPF function/struct: hello\n",
|
|
"Found BPF function/struct: LICENSE\n",
|
|
"Found BPF map: hist\n",
|
|
"Processing BPF map: hist\n",
|
|
"Creating HashMap map: hist\n",
|
|
"Map parameters: {'type': 'HASH', 'key': 'c_int32', 'value': 'c_uint64', 'max_entries': 4096}\n",
|
|
"Created BPF map: hist\n",
|
|
"Found probe_string of hello: tracepoint/syscalls/sys_enter_clone\n",
|
|
"Pre-allocated variable process_id for helper\n",
|
|
"Pre-allocated variable one of type c_int64\n",
|
|
"Pre-allocated variable prev for map\n",
|
|
"Pre-allocated variable previous_value of type c_int64\n",
|
|
"Local symbol table: dict_keys(['process_id', 'one', 'prev', 'previous_value'])\n",
|
|
"Processing statement: Assign(targets=[Name(id='process_id', ctx=Store())], value=Call(func=Name(id='pid', ctx=Load()), args=[], keywords=[]))\n",
|
|
"Handling assignment to Name(id='process_id', ctx=Store())\n",
|
|
"Assignment call type: pid\n",
|
|
"Assigned constant pid to process_id\n",
|
|
"Processing statement: Assign(targets=[Name(id='one', ctx=Store())], value=Constant(value=1))\n",
|
|
"Handling assignment to Name(id='one', ctx=Store())\n",
|
|
"Assigned constant 1 to one\n",
|
|
"Processing statement: Assign(targets=[Name(id='prev', ctx=Store())], value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='lookup', ctx=Load()), args=[Name(id='process_id', ctx=Load())], keywords=[]))\n",
|
|
"Handling assignment to Name(id='prev', ctx=Store())\n",
|
|
"Assignment call attribute: Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='lookup', ctx=Load())\n",
|
|
"{}\n",
|
|
"Processing statement: If(test=Name(id='prev', ctx=Load()), body=[Assign(targets=[Name(id='previous_value', ctx=Store())], value=BinOp(left=Name(id='prev', ctx=Load()), op=Add(), right=Constant(value=1))), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[])), Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[])), Return(value=Call(func=Name(id='c_int64', ctx=Load()), args=[Constant(value=0)], keywords=[]))], orelse=[Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[]))])\n",
|
|
"Handling if statement\n",
|
|
"Processing statement: Assign(targets=[Name(id='previous_value', ctx=Store())], value=BinOp(left=Name(id='prev', ctx=Load()), op=Add(), right=Constant(value=1)))\n",
|
|
"Handling assignment to Name(id='previous_value', ctx=Store())\n",
|
|
"; ModuleID = \"/tmp/tmp98sm2v54.py\"\n",
|
|
"target triple = \"bpf\"\n",
|
|
"target datalayout = \"e-m:e-p:64:64-i64:64-i128:128-n32:64-S128\"\n",
|
|
"\n",
|
|
"@\"hist\" = dso_local global {ptr, ptr, ptr, ptr} zeroinitializer, section \".maps\", align 8, !dbg !22\n",
|
|
"define dso_local i64 @\"hello\"(ptr nocapture %\".1\") noinline nounwind optnone section \"tracepoint/syscalls/sys_enter_clone\"\n",
|
|
"{\n",
|
|
"entry:\n",
|
|
" %\"process_id\" = alloca i64, align 8\n",
|
|
" %\"one\" = alloca i64, align 8\n",
|
|
" %\"prev\" = alloca i64*\n",
|
|
" %\"previous_value\" = alloca i64, align 8\n",
|
|
" %\".3\" = inttoptr i64 14 to i64 ()*\n",
|
|
" %\".4\" = call i64 %\".3\"()\n",
|
|
" %\".5\" = and i64 %\".4\", 4294967295\n",
|
|
" store i64 %\".5\", i64* %\"process_id\"\n",
|
|
" store i64 1, i64* %\"one\"\n",
|
|
" %\".8\" = inttoptr i64 1 to ptr (ptr, ptr)*\n",
|
|
" %\".9\" = call ptr %\".8\"({ptr, ptr, ptr, ptr}* @\"hist\", i64* %\"process_id\")\n",
|
|
" store ptr %\".9\", i64** %\"prev\"\n",
|
|
" %\".11\" = load i64*, i64** %\"prev\"\n",
|
|
" %\".12\" = icmp ne i64* %\".11\", null\n",
|
|
" br i1 %\".12\", label %\"if.then\", label %\"if.else\"\n",
|
|
"if.then:\n",
|
|
"if.end:\n",
|
|
"if.else:\n",
|
|
"}\n",
|
|
"\n",
|
|
"!llvm.dbg.cu = !{ !1 }\n",
|
|
"!0 = !DIFile(directory: \"/tmp\", filename: \"/tmp/tmp98sm2v54.py\")\n",
|
|
"!1 = distinct !DICompileUnit(emissionKind: 1, file: !0, isOptimized: true, language: 29, nameTableKind: 0, producer: \"PythonBPF DSL Compiler\", runtimeVersion: 0, splitDebugInlining: false)\n",
|
|
"!2 = !DIBasicType(encoding: 7, name: \"unsigned int\", size: 32)\n",
|
|
"!3 = !DIBasicType(encoding: 7, name: \"unsigned long long\", size: 64)\n",
|
|
"!4 = !DISubrange(count: 1)\n",
|
|
"!5 = !{ !4 }\n",
|
|
"!6 = !DICompositeType(baseType: !2, elements: !5, size: 32, tag: 1)\n",
|
|
"!7 = !DIDerivedType(baseType: !6, size: 64, tag: 15)\n",
|
|
"!8 = !DIDerivedType(baseType: !2, size: 64, tag: 15)\n",
|
|
"!9 = !DIDerivedType(baseType: !3, size: 64, tag: 15)\n",
|
|
"!10 = !DIDerivedType(baseType: !7, file: !0, name: \"type\", offset: 0, size: 64, tag: 13)\n",
|
|
"!11 = !DIDerivedType(baseType: !8, file: !0, name: \"key\", offset: 64, size: 64, tag: 13)\n",
|
|
"!12 = !DIDerivedType(baseType: !9, file: !0, name: \"value\", offset: 128, size: 64, tag: 13)\n",
|
|
"!13 = !DISubrange(count: 4096)\n",
|
|
"!14 = !{ !13 }\n",
|
|
"!15 = !DICompositeType(baseType: !2, elements: !14, size: 32, tag: 1)\n",
|
|
"!16 = !DIDerivedType(baseType: !15, size: 64, tag: 15)\n",
|
|
"!17 = !DIDerivedType(baseType: !16, file: !0, name: \"max_entries\", offset: 192, size: 64, tag: 13)\n",
|
|
"!18 = !{ !10, !11, !12, !17 }\n",
|
|
"!19 = distinct !DICompositeType(elements: !18, file: !0, size: 256, tag: 19)\n",
|
|
"!20 = distinct !DIGlobalVariable(file: !0, isDefinition: true, isLocal: false, name: \"hist\", scope: !1, type: !19)\n",
|
|
"!21 = !DIExpression()\n",
|
|
"!22 = !DIGlobalVariableExpression(expr: !21, var: !20)\n",
|
|
"left is %\".15\" = load i64, i64* %\".14\", right is i64 1, op is <ast.Add object at 0x70244bec1410>\n",
|
|
"Processing statement: Expr(value=Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[]))\n",
|
|
"Handling expression: Expr(value=Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[]))\n",
|
|
"Evaluating expression: Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[])\n",
|
|
"Value in f-string: Constant(value='count: ')\n",
|
|
"Value in f-string: FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1)\n",
|
|
"Formatted value: FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1)\n",
|
|
"Formatted value variable: %\"previous_value\" = alloca i64, align 8 i64\n",
|
|
"Value in f-string: Constant(value=' with ')\n",
|
|
"Value in f-string: FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)\n",
|
|
"Formatted value: FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)\n",
|
|
"Formatted value variable: %\"process_id\" = alloca i64, align 8 i64\n",
|
|
"Evaluating expression: Name(id='previous_value', ctx=Load())\n",
|
|
"Evaluating expression: Name(id='process_id', ctx=Load())\n",
|
|
"Processing statement: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[]))\n",
|
|
"Handling expression: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[]))\n",
|
|
"Evaluating expression: Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[])\n",
|
|
"Handling method call: Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load())\n",
|
|
"{}\n",
|
|
"Processing statement: Return(value=Call(func=Name(id='c_int64', ctx=Load()), args=[Constant(value=0)], keywords=[]))\n",
|
|
"Processing statement: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[]))\n",
|
|
"Handling expression: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[]))\n",
|
|
"Evaluating expression: Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[])\n",
|
|
"Handling method call: Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load())\n",
|
|
"{}\n",
|
|
"Processing statement: Return(value=Call(func=Name(id='c_int64', ctx=Load()), args=[Constant(value=0)], keywords=[]))\n",
|
|
"IR written to /tmp/tmpx05plfu1.ll\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"@bpf\n",
|
|
"@map\n",
|
|
"def hist() -> HashMap:\n",
|
|
" return HashMap(key=c_int32, value=c_uint64, max_entries=4096)\n",
|
|
"\n",
|
|
"@bpf\n",
|
|
"@section(\"tracepoint/syscalls/sys_enter_clone\")\n",
|
|
"def hello(ctx: c_void_p) -> c_int64:\n",
|
|
" process_id = pid()\n",
|
|
" one = 1\n",
|
|
" prev = hist().lookup(process_id)\n",
|
|
" if prev:\n",
|
|
" previous_value = prev + 1\n",
|
|
" print(f\"count: {previous_value} with {process_id}\")\n",
|
|
" hist().update(process_id, previous_value)\n",
|
|
" return c_int64(0)\n",
|
|
" else:\n",
|
|
" hist().update(process_id, one)\n",
|
|
" return c_int64(0)\n",
|
|
"\n",
|
|
"\n",
|
|
"@bpf\n",
|
|
"@bpfglobal\n",
|
|
"def LICENSE() -> str:\n",
|
|
" return \"GPL\"\n",
|
|
"\n",
|
|
"b = BPF()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "93fae9f8-464e-48d6-b61e-57b9f93e508a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Recording\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAOxxJREFUeJzt3XlcFuX+//H3Dcoa4MoiEK64C65FllhipOQR66jZgnuLWpqlHU99XbKi8mhquZxOqXXMPbXSXMg1lTJLTM00V1IBdxBKVJjfH/68T3eAwi1ww/R6Ph7zeJy55rrm/szk8X57zcw9FsMwDAEAAJiEk6MLAAAAKE6EGwAAYCqEGwAAYCqEGwAAYCqEGwAAYCqEGwAAYCqEGwAAYCqEGwAAYCqEGwAAYCqEGwDFwmKxaOzYsdb1OXPmyGKx6OjRo7e87+LcFwDzI9wAZcTu3bv197//XSEhIXJzc1NgYKA6duyod99919GlwQS2bdumsWPH6sKFC44uBShxhBugDNi2bZtatWqlXbt2aeDAgXrvvfc0YMAAOTk5acqUKY4uDyawbds2jRs3jnCDv4QKji4AgPT666/Lx8dH3333nSpVqmSz7dSpU44pCgDKKWZugDLg0KFDaty4cZ5gI0m+vr7W/x0ZGamwsLB891G/fn1FR0db1xcsWKCWLVvKy8tL3t7eatq0aZ5ZoAsXLuj5559XzZo15erqqqCgIMXFxenMmTOSpMuXL2v06NFq2bKlfHx85OnpqXvuuUcbNmwohqP+n59//lk9evRQ9erV5e7urvr16+vll1++6bjp06ercePGcnV1VY0aNTR48OA8MxPt27dXkyZN9NNPP+nee++Vh4eHAgMD9fbbb+fZX3Z2tsaMGaO6devK1dVVwcHBGjlypLKzswt1HN9++606d+6sypUry9PTU82aNctzztevX6977rlHnp6eqlSpkrp27ap9+/bZ9OnTp49q1qyZZ/9jx46VxWKxabNYLBoyZIiWL1+uJk2ayNXVVY0bN9bq1attxo0YMUKSVKtWLVksFpt7mBISEnT33XerUqVKuu2221S/fn3985//LNQxA2URMzdAGRASEqLExETt2bNHTZo0KbDfE088oYEDB+bp99133+nAgQN65ZVXJF37surVq5c6dOigt956S5K0b98+bd26VUOHDpUkZWZm6p577tG+ffvUr18/tWjRQmfOnNHnn3+u48ePq1q1asrIyNAHH3ygXr16aeDAgbp48aI+/PBDRUdHa/v27QoPD7/lY//xxx91zz33qGLFinryySdVs2ZNHTp0SF988YVef/31AseNHTtW48aNU1RUlJ555hnt379fM2bM0HfffaetW7eqYsWK1r7nz5/XAw88oIceekg9evTQkiVL9NJLL6lp06bq1KmTJCk3N1d/+9vftGXLFj355JNq2LChdu/erXfeeUcHDhzQ8uXLb3gcCQkJevDBBxUQEKChQ4fK399f+/bt04oVK6zn/KuvvlKnTp1Uu3ZtjR07Vr///rveffddtW3bVj/88EO+gaYwtmzZoqVLl2rQoEHy8vLS1KlT9fDDDys5OVlVq1bVQw89pAMHDmj+/Pl65513VK1aNUlS9erVtXfvXj344INq1qyZXn31Vbm6uurgwYPaunWrXbUAZYIBwOHWrl1rODs7G87OzkZERIQxcuRIY82aNcbly5dt+l24cMFwc3MzXnrpJZv25557zvD09DQyMzMNwzCMoUOHGt7e3sbVq1cL/MzRo0cbkoylS5fm2Zabm2sYhmFcvXrVyM7Ottl2/vx5w8/Pz+jXr59NuyRjzJgx1vXZs2cbkowjR47c8NjbtWtneHl5GceOHcu3hvz2derUKcPFxcW4//77jZycHGu/9957z5BkzJo1y9oWGRlpSDI+/vhja1t2drbh7+9vPPzww9a2//73v4aTk5Px9ddf29Qxc+ZMQ5KxdevWAo/h6tWrRq1atYyQkBDj/PnzBR5HeHi44evra5w9e9batmvXLsPJycmIi4uztvXu3dsICQnJ8zljxowx/vzXtiTDxcXFOHjwoM0+JRnvvvuutW3ChAn5/vd45513DEnG6dOnCzw+oLzhshRQBnTs2FGJiYn629/+pl27duntt99WdHS0AgMD9fnnn1v7+fj4qGvXrpo/f74Mw5Ak5eTkaOHChYqNjZWnp6ckqVKlSsrKylJCQkKBn/npp58qLCxM3bp1y7Pt+qUPZ2dnubi4SLo2s3Hu3DldvXpVrVq10g8//HDLx3369Glt3rxZ/fr10+23355vDfn56quvdPnyZQ0bNkxOTv/7a2zgwIHy9vbWypUrbfrfdtttevzxx63rLi4uatOmjQ4fPmxtW7x4sRo2bKgGDRrozJkz1uW+++6TpBteitu5c6eOHDmiYcOG5bm0eP04UlJSlJSUpD59+qhKlSrW7c2aNVPHjh315ZdfFrj/m4mKilKdOnVs9unt7W1zfAW5Xu9nn32m3Nxcu2sAyhLCDVBGtG7dWkuXLtX58+e1fft2jRo1ShcvXtTf//53/fTTT9Z+cXFxSk5O1tdffy3p2hd9WlqannjiCWufQYMGKTQ0VJ06dVJQUJD69etncw+GdO0+nxtdArvuo48+UrNmzeTm5qaqVauqevXqWrlypdLT02/5mK9/+Ramjj86duyYpGv3Gf2Ri4uLateubd1+XVBQUJ6wVLlyZZ0/f966/ssvv2jv3r2qXr26zRIaGirpxjd2Hzp06KbHUVDNktSwYUOdOXNGWVlZBY6/kT8HQynv8RWkZ8+eatu2rQYMGCA/Pz898sgjWrRoEUEH5Rr33ABljIuLi1q3bq3WrVsrNDRUffv21eLFizVmzBhJUnR0tPz8/DR37ly1a9dOc+fOlb+/v6Kioqz78PX1VVJSktasWaNVq1Zp1apVmj17tuLi4vTRRx8Vupa5c+eqT58+io2N1YgRI+Tr6ytnZ2fFx8dbv9DLA2dn53zbr89+Sddmppo2bapJkybl2zc4OLhEastPQbNWOTk5+bYX5vgK4u7urs2bN2vDhg1auXKlVq9erYULF+q+++7T2rVrC9w3UJYxcwOUYa1atZJ07ZLGdc7Oznr00Ue1ZMkSnT9/XsuXL1evXr3yfAm5uLioS5cumj59ug4dOqSnnnpKH3/8sQ4ePChJqlOnjvbs2XPDz1+yZIlq166tpUuX6oknnlB0dLSioqJ06dKlYjm+2rVrS9JN6/izkJAQSdL+/ftt2i9fvqwjR45YtxdFnTp1dO7cOXXo0EFRUVF5lvxmXP44VrrxcRRUs3TtabFq1apZLytWrlw539+j+fOMVFHc6DKfk5OTOnTooEmTJumnn37S66+/rvXr1xf7U3FAaSHcAGXAhg0b8v1X9vX7MP78xfrEE0/o/Pnzeuqpp5SZmWlzP4kknT171mbdyclJzZo1kyTrY80PP/ywdu3apWXLluX53Ou1XA9Mf6zt22+/VWJiYpGOryDVq1dXu3btNGvWLCUnJ+dbQ36ioqLk4uKiqVOn2vT78MMPlZ6erpiYmCLX0qNHD504cUL/+c9/8mz7/fffb3jJqEWLFqpVq5YmT56cJ5Rcry8gIEDh4eH66KOPbPrs2bNHa9euVefOna1tderUUXp6un788UdrW0pKSr7/rQrrenD6c33nzp3L0/f6U3CFfQQeKGu4LAWUAc8++6x+++03devWTQ0aNNDly5e1bds2LVy4UDVr1lTfvn1t+jdv3lxNmjSx3gTbokULm+0DBgzQuXPndN999ykoKEjHjh3Tu+++q/DwcDVs2FCSNGLECC1ZskTdu3dXv3791LJlS507d06ff/65Zs6cqbCwMD344INaunSpunXrppiYGB05ckQzZ85Uo0aNlJmZWSzHPnXqVN19991q0aKFnnzySdWqVUtHjx7VypUrlZSUlO+Y6tWra9SoURo3bpweeOAB/e1vf9P+/fs1ffp0tW7dOk/YK4wnnnhCixYt0tNPP60NGzaobdu2ysnJ0c8//6xFixZpzZo11pm0P3NyctKMGTPUpUsXhYeHq2/fvgoICNDPP/+svXv3as2aNZKkCRMmqFOnToqIiFD//v2tj4L7+PjYvJfrkUce0UsvvaRu3brpueee02+//aYZM2YoNDTU7hu5W7ZsKUl6+eWX9cgjj6hixYrq0qWLXn31VW3evFkxMTEKCQnRqVOnNH36dAUFBenuu++267MAh3PYc1oArFatWmX069fPaNCggXHbbbcZLi4uRt26dY1nn33WSEtLy3fM22+/bUgy3njjjTzblixZYtx///2Gr6+v4eLiYtx+++3GU089ZaSkpNj0O3v2rDFkyBAjMDDQcHFxMYKCgozevXsbZ86cMQzj2mPMb7zxhhESEmK4uroazZs3N1asWJHvo8qy81FwwzCMPXv2GN26dTMqVapkuLm5GfXr1zf+7//+76b7eu+994wGDRoYFStWNPz8/Ixnnnkmz6PYkZGRRuPGjfN8Zn7HcPnyZeOtt94yGjdubLi6uhqVK1c2WrZsaYwbN85IT0+/6XFs2bLF6Nixo+Hl5WV4enoazZo1s3kc2zAM46uvvjLatm1ruLu7G97e3kaXLl2Mn376Kc++1q5dazRp0sRwcXEx6tevb8ydO7fAR8EHDx6cZ3xISIjRu3dvm7bx48cbgYGBhpOTk/V8rlu3zujatatRo0YNw8XFxahRo4bRq1cv48CBAzc9XqCsshhGIe44A1DmTJkyRc8//7yOHj2a79MyAPBXRbgByiHDMBQWFqaqVaty0ycA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AABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMxaHhJj4+Xq1bt5aXl5d8fX0VGxur/fv333Tc4sWL1aBBA7m5ualp06b68ssvS6FaAABQHjg03GzatEmDBw/WN998o4SEBF25ckX333+/srKyChyzbds29erVS/3799fOnTsVGxur2NhY7dmzpxQrBwAAZZXFMAzD0UVcd/r0afn6+mrTpk1q165dvn169uyprKwsrVixwtp25513Kjw8XDNnzrzpZ2RkZMjHx0fp6eny9vYuttoBACgJNf+x0tElFNnRN2OKfZ9F+f4uU/fcpKenS5KqVKlSYJ/ExERFRUXZtEVHRysxMTHf/tnZ2crIyLBZAACAeVVwdAHX5ebmatiwYWrbtq2aNGlSYL/U1FT5+fnZtPn5+Sk1NTXf/vHx8Ro3blyx1nojJGwAAByrzMzcDB48WHv27NGCBQuKdb+jRo1Senq6dfn111+Ldf8AAKBsKRMzN0OGDNGKFSu0efNmBQUF3bCvv7+/0tLSbNrS0tLk7++fb39XV1e5uroWW60AAKBsc+jMjWEYGjJkiJYtW6b169erVq1aNx0TERGhdevW2bQlJCQoIiKipMoEAADliENnbgYPHqx58+bps88+k5eXl/W+GR8fH7m7u0uS4uLiFBgYqPj4eEnS0KFDFRkZqYkTJyomJkYLFizQjh079P777zvsOAAAQNnh0JmbGTNmKD09Xe3bt1dAQIB1WbhwobVPcnKyUlJSrOt33XWX5s2bp/fff19hYWFasmSJli9ffsObkAEAwF+HQ2duCvMTOxs3bszT1r17d3Xv3r0EKgIAAOVdmXlaCgAAoDgQbgAAgKkQbgAAgKkQbgAAgKkQbgAAgKkQbgAAgKkQbgAAgKkQbgAAgKkQbgAAgKkQbgAAgKnYFW4OHz5c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AKWpgiM/vFq1anJ2dlZaWppNe1pamvz9/Qu1j4oVK6p58+Y6ePBgvttdXV3l6up6y7UCAIDywaEzNy4uLmrZsqXWrVtnbcvNzdW6desUERFRqH3k5ORo9+7dCggIKKkyAQBAOeLQmRtJGj58uHr37q1WrVqpTZs2mjx5srKystS3b19JUlxcnAIDAxUfHy9JevXVV3XnnXeqbt26unDhgiZMmKBjx45pwIABjjwMAABQRjg83PTs2VOnT5/W6NGjlZqaqvDwcK1evdp6k3FycrKcnP43wXT+/HkNHDhQqampqly5slq2bKlt27apUaNGjjoEAABQhlgMwzAcXURpysjIkI+Pj9LT0+Xt7V3s+6/5j5XFvs+SdvTNGEeXAAAoAN8r1xTl+7vcPS0FAABwI4QbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKoQbAABgKmUi3EybNk01a9aUm5ub7rjjDm3fvv2G/RcvXqwGDRrIzc1NTZs21ZdffllKlQIAgLLO4eFm4cKFGj58uMaMGaMffvhBYWFhio6O1qlTp/Ltv23bNvXq1Uv9+/fXzp07FRsbq9jYWO3Zs6eUKwcAAGWRw8PNpEmTNHDgQPXt21eNGjXSzJkz5eHhoVmzZuXbf8qUKXrggQc0YsQINWzYUOPHj1eLFi303nvvlXLlAACgLHJouLl8+bK+//57RUVFWducnJwUFRWlxMTEfMckJiba9Jek6OjoAvsDAIC/lgqO/PAzZ84oJydHfn5+Nu1+fn76+eef8x2Tmpqab//U1NR8+2dnZys7O9u6np6eLknKyMi4ldILlJv9W4nstySV1LkAANw6vlds92kYxk37OjTclIb4+HiNGzcuT3twcLADqimbfCY7ugIAgJmU5PfKxYsX5ePjc8M+Dg031apVk7Ozs9LS0mza09LS5O/vn+8Yf3//IvUfNWqUhg8fbl3Pzc3VuXPnVLVqVVkslls8AlsZGRkKDg7Wr7/+Km9v72LdN/6H81w6OM+lg/NcejjXpaOkzrNhGLp48aJq1Khx074ODTcuLi5q2bKl1q1bp9jYWEnXwse6des0ZMiQfMdERERo3bp1GjZsmLUtISFBERER+fZ3dXWVq6urTVulSpWKo/wCeXt783+cUsB5Lh2c59LBeS49nOvSURLn+WYzNtc5/LLU8OHD1bt3b7Vq1Upt2rTR5MmTlZWVpb59+0qS4uLiFBgYqPj4eEnS0KFDFRkZqYkTJyomJkYLFizQjh079P777zvyMAAAQBnh8HDTs2dPnT59WqNHj1ZqaqrCw8O1evVq603DycnJcnL630Ndd911l+bNm6dXXnlF//znP1WvXj0tX75cTZo0cdQhAACAMsTh4UaShgwZUuBlqI0bN+Zp6969u7p3717CVRWdq6urxowZk+cyGIoX57l0cJ5LB+e59HCuS0dZOM8WozDPVAEAAJQTDv+FYgAAgOJEuAEAAKZCuAEAAKZCuAEAAKZCuCmkzZs3q0uXLqpRo4YsFouWL19+0zEbN25UixYt5Orqqrp162rOnDklXqcZFPVcL126VB07dlT16tXl7e2tiIgIrVmzpnSKLcfs+TN93datW1WhQgWFh4eXWH1mYc95zs7O1ssvv6yQkBC5urqqZs2amjVrVskXW47Zc54/+eQThYWFycPDQwEBAerXr5/Onj1b8sWWY/Hx8WrdurW8vLzk6+ur2NhY7d+//6bjFi9erAYNGsjNzU1NmzbVl19+WaJ1Em4KKSsrS2FhYZo2bVqh+h85ckQxMTG69957lZSUpGHDhmnAgAF86RZCUc/15s2b1bFjR3355Zf6/vvvde+996pLly7auXNnCVdavhX1PF934cIFxcXFqUOHDiVUmbnYc5579OihdevW6cMPP9T+/fs1f/581a9fvwSrLP+Kep63bt2quLg49e/fX3v37tXixYu1fft2DRw4sIQrLd82bdqkwYMH65tvvlFCQoKuXLmi+++/X1lZWQWO2bZtm3r16qX+/ftr586dio2NVWxsrPbs2VNyhRooMknGsmXLbthn5MiRRuPGjW3aevbsaURHR5dgZeZTmHOdn0aNGhnjxo0r/oJMqijnuWfPnsYrr7xijBkzxggLCyvRusymMOd51apVho+Pj3H27NnSKcqECnOeJ0yYYNSuXdumberUqUZgYGAJVmY+p06dMiQZmzZtKrBPjx49jJiYGJu2O+64w3jqqadKrC5mbkpIYmKioqKibNqio6OVmJjooIr+OnJzc3Xx4kVVqVLF0aWYzuzZs3X48GGNGTPG0aWY1ueff65WrVrp7bffVmBgoEJDQ/Xiiy/q999/d3RpphIREaFff/1VX375pQzDUFpampYsWaLOnTs7urRyJT09XZJu+PetI74Py8QvFJtRamqq9RUS1/n5+SkjI0O///673N3dHVSZ+f3rX/9SZmamevTo4ehSTOWXX37RP/7xD3399deqUIG/OkrK4cOHtWXLFrm5uWnZsmU6c+aMBg0apLNnz2r27NmOLs802rZtq08++UQ9e/bUpUuXdPXqVXXp0qXIl2n/ynJzczVs2DC1bdv2hq9AKuj7MDU1tcRqY+YGpjJv3jyNGzdOixYtkq+vr6PLMY2cnBw9+uijGjdunEJDQx1djqnl5ubKYrHok08+UZs2bdS5c2dNmjRJH330EbM3xeinn37S0KFDNXr0aH3//fdavXq1jh49qqefftrRpZUbgwcP1p49e7RgwQJHl5IH//wqIf7+/kpLS7NpS0tLk7e3N7M2JWTBggUaMGCAFi9enGcKFLfm4sWL2rFjh3bu3Gl9D1xubq4Mw1CFChW0du1a3XfffQ6u0hwCAgIUGBgoHx8fa1vDhg1lGIaOHz+uevXqObA684iPj1fbtm01YsQISVKzZs3k6empe+65R6+99poCAgIcXGHZNmTIEK1YsUKbN29WUFDQDfsW9H3o7+9fYvUxc1NCIiIitG7dOpu2hIQERUREOKgic5s/f7769u2r+fPnKyYmxtHlmI63t7d2796tpKQk6/L000+rfv36SkpK0h133OHoEk2jbdu2OnnypDIzM61tBw4ckJOT002/RFB4v/32m5ycbL8CnZ2dJUkGr1wskGEYGjJkiJYtW6b169erVq1aNx3jiO9DZm4KKTMzUwcPHrSuHzlyRElJSapSpYpuv/12jRo1SidOnNDHH38sSXr66af13nvvaeTIkerXr5/Wr1+vRYsWaeXKlY46hHKjqOd63rx56t27t6ZMmaI7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",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"\n",
|
|
"b.load_and_attach()\n",
|
|
"hist = BpfMap(b, hist)\n",
|
|
"print(\"Recording\")\n",
|
|
"time.sleep(10)\n",
|
|
"\n",
|
|
"counts = list(hist.values())\n",
|
|
"\n",
|
|
"plt.hist(counts, bins=10)\n",
|
|
"plt.xlabel(\"Clone calls per PID\")\n",
|
|
"plt.ylabel(\"Frequency\")\n",
|
|
"plt.title(\"Syscall clone counts\")\n",
|
|
"plt.show()"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.12.3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|