ÿØÿà JFIF    ÿÛ „ ( %!1!%*+...983,7(-.- __pycache__/containers.cpython-36.opt-1.pyc000064400000006242152344707330014522 0ustar003 :)gk@sddZddZddZdS)cCs|sdSd}|jd|S)NzV static inline int _cgroup_filter() { return 0; } z BPF_TABLE_PINNED("hash", u64, u64, cgroupset, 1024, "CGROUP_PATH"); static inline int _cgroup_filter() { u64 cgroupid = bpf_get_current_cgroup_id(); return cgroupset.lookup(&cgroupid) == NULL; } Z CGROUP_PATH)replace) cgroupmaptextr /usr/lib/python3.6/containers.py_cgroup_filter_func_writers rcCs|sdSd}|jd|S)NzU static inline int _mntns_filter() { return 0; } a #include #include #include /* see mountsnoop.py: * XXX: struct mnt_namespace is defined in fs/mount.h, which is private * to the VFS and not installed in any kernel-devel packages. So, let's * duplicate the important part of the definition. There are actually * more members in the real struct, but we don't need them, and they're * more likely to change. */ struct mnt_namespace { // This field was removed in https://github.com/torvalds/linux/commit/1a7b8969e664d6af328f00fe6eb7aabd61a71d13 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0) atomic_t count; #endif struct ns_common ns; }; /* * To add mountsnoop support for --selector option, we need to call * filter_by_containers(). * This function adds code which defines struct mnt_namespace. * The problem is that this struct is also defined in mountsnoop BPF code. * To avoid redefining it in mountnsoop code, we define * MNT_NAMESPACE_DEFINED here. * Then, in mountsnoop code, the struct mnt_namespace definition is guarded * by: * #ifndef MNT_NAMESPACE_DEFINED * // ... * #endif */ #define MNT_NAMESPACE_DEFINED BPF_TABLE_PINNED("hash", u64, u32, mount_ns_set, 1024, "MOUNT_NS_PATH"); static inline int _mntns_filter() { struct task_struct *current_task; struct nsproxy *nsproxy; struct mnt_namespace *mnt_ns; unsigned int inum; u64 ns_id; current_task = (struct task_struct *)bpf_get_current_task(); if (bpf_probe_read_kernel(&nsproxy, sizeof(nsproxy), ¤t_task->nsproxy)) return 0; if (bpf_probe_read_kernel(&mnt_ns, sizeof(mnt_ns), &nsproxy->mnt_ns)) return 0; if (bpf_probe_read_kernel(&inum, sizeof(inum), &mnt_ns->ns.inum)) return 0; ns_id = (u64) inum; return mount_ns_set.lookup(&ns_id) == NULL; } Z MOUNT_NS_PATH)r)mntnsmaprrrr_mntns_filter_func_writer"s;rcCs$d}t|j}t|j}|||S)Nzv static inline int container_should_be_filtered() { return _cgroup_filter() || _mntns_filter(); } )rrrr)argsZfilter_by_containers_textZcgroupmap_textZ mntnsmap_textrrrfilter_by_containersgs  r N)rrr rrrrsE__pycache__/disassembler.cpython-36.opt-1.pyc000064400000030363152344707330015033 0ustar003 :)gP@sddlmZddlZddlmZGdddejZGdddejZGd d d ej Z Gd d d ejZ Gd ddZ dddZ ddZddZGdddZdddZdS))linesepN)get_table_type_namec@s eZdZdejfdejfgZdS) OffsetUnionZoffsetuoffsetN)__name__ __module__ __qualname__ctZc_uint16Zc_int16_fields_r r "/usr/lib/python3.6/disassembler.pyrsrc@s eZdZdejfdejfgZdS)ImmUnionimmuimmN)rrr r Zc_uint32Zc_int32r r r r r rsrc@s@eZdZdZd ZdejfdejdfdejdfdefdefgZ dS) BPFInstrFieldsroiopcodedstsrcN)rr) rrr _pack_ _anonymous_r Zc_uint8rrr r r r r rs  rc@s&eZdZdZdZdefdejfgZdS)BPFInstrrsinstrN) rrr rrrr c_uint64r r r r r r"srcd@seZdZdZdddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;dd?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^g]Zdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*dǜaZeddɄZdeS(+ BPFDecoderrZunspecZmap_lookup_elemZmap_update_elemZmap_delete_elemZ probe_readZ ktime_get_nsZ trace_printkZget_prandom_u32Zget_smp_processor_idZskb_store_bytesZl3_csum_replaceZl4_csum_replaceZ tail_callZclone_redirectZget_current_pid_tgidZget_current_uid_gidZget_current_commZget_cgroup_classidZ skb_vlan_pushZ skb_vlan_popZskb_get_tunnel_keyZskb_set_tunnel_keyZperf_event_readZredirectZget_route_realmZperf_event_outputZskb_load_bytesZ get_stackidZ csum_diffZskb_get_tunnel_optZskb_set_tunnel_optZskb_change_protoZskb_change_typeZskb_under_cgroupZget_hash_recalcZget_current_taskZprobe_write_userZcurrent_task_under_cgroupZskb_change_tailZ skb_pull_dataZ csum_updateZset_hash_invalidZget_numa_node_idZskb_change_headZxdp_adjust_headZprobe_read_strZget_socket_cookieZget_socket_uidZset_hashZ setsockoptZskb_adjust_roomZ redirect_mapZsk_redirect_mapZsock_map_updateZxdp_adjust_metaZperf_event_read_valueZperf_prog_read_valueZ getsockoptZoverride_returnZsock_ops_cb_flags_setZmsg_redirect_mapZmsg_apply_bytesZmsg_cork_bytesZ msg_pull_dataZbindZxdp_adjust_tailZskb_get_xfrm_stateZ get_stackZskb_load_bytes_relativeZ fib_lookupZsock_hash_updateZmsg_redirect_hashZsk_redirect_hashZlwt_push_encapZlwt_seg6_store_bytesZlwt_seg6_adjust_srhZlwt_seg6_actionZ rc_repeatZ rc_keydownZ skb_cgroup_idZget_current_cgroup_idZget_local_storageZsk_select_reuseportZskb_ancestor_cgroup_idZ sk_lookup_tcpZ sk_lookup_udpZ sk_releaseZ map_push_elemZ map_pop_elemZ map_peek_elemZ msg_push_dataZ msg_pop_dataZrc_pointer_reladd32dstimm+= jajoffN@adddstsrcsub32-=jeq jdstimmoff==sublddw jdstsrcoffldabswldabsmul32*=jgt>mulldabshldabsbdiv32/=jge>=divldabsdwldindwldindor32 dstimm_bw|=jset&orldindhldindband32&=jne!=andldinddwldxw ldstsrcoffstw sdstoffimmstxw sdstoffsrclsh32<<=jsgts>lshldxhsthstxhldxbstbstxbrsh32>>=jsges>=rshldxdwstdwstxdwneg32r~callnegmod32%=exitmodxor32^=jlt<xormov32=jle<=movarsh32s>>=jslts<arshjsles<=endian32endian)ar r"$%'(,-/04578<=?r%DEGHLMOPTUWX\]_abcdegijklmoqrstuwyz{|}c Csy|j|j\}}}}|dkr6d|j||jfdfS|dkrTd|j||jfdfS|dkr|dd|j||jd fdfS|d krd |j||jfdfS|d krd |j||jd|j||jd fdfS|dkrd|j||jd|j||jd fdfS|dkr^|dkrtd|jdkr|jB}d|j|fd fS|dkrzd||jfdfS|dkrd||jd|jfdfS|dkrd|j||jd|jfdfS|dkrd||jd|j|jfdfS|dkrd||jd|j|jfdfS|dkr8d |j|||jfdfS|d!kr|j|jkryd"||j |j|jfdfSt k rd#||jfdfSXd$|d|jfdfS|d%kr|dfStd&Wnt k rd'|jSXdS)(Nr z r%d %s %drrDz r%d %s 0x%xr$z goto %s <%d>z%+drr'z r%d %s r%dr+zif r%d %s %d goto pc%s <%d>r/zif r%d %s r%d goto pc%s <%d>r.z1lddw requires two instructions to be disassembledzr%d = r"z r%d = 0x%xr1zr0 = *(u%s*)skb[%s]rBzr0 = *(u%d*)skb[r%d %s]rRzr%d = *(u%d*)(r%d %s)rTz*(u%d*)(r%d %s) = %drVz*(u%d*)(r%d %s) = r%drzr%d = %s (u%s)r%drlz %s bpf_%s#%dz%s z%s %srpzunknown opcode classzunknown <0x%x>) opcodesrrrrrr ExceptionBPF_PSEUDO_CALL bpf_helpers IndexErrorKeyError) clsrww1nameZopclassopbitsrr r r decodesl                 zBPFDecoder.decode)rr r!r")r#r$Nr%)r&r r!r%)rr'r!r")r&r'r!r%)r(r r)r")r*r+r,r%)r-r r)r%)r.r.Nr%)r(r'r)r")r*r/r,r%)r-r'r)r%)r0r1Nr")r2r r3r")r4r+r5r%)r6r r3r%)r7r1Nr8)r2r'r3r")r4r/r5r%)r6r'r3r%)r9r1Nr:)r;r r<r")r=r+r>r%)r?r r<r%)r@r1Nr%)r;r'r<r")r=r/r>r%)r?r'r<r%)rArBNr")rCrDrEr")rFr+rGr%)rHrDrEr%)rIrBNr8)rCr'rEr")rFr/rGr%)rHr'rEr%)rJrBNr:)rKrDrLr")rMr+rNr%)rOrDrLr%)rPrBNr%)rKr'rLr")rMr/rNr%)rOr'rLr%)rQrRNr")rSrTNr")rUrVNr")rWr rXr")rYr+rZr%)r[r rXr%)r\rRNr8)r]rTNr8)r^rVNr8)rWr'rXr")rYr/rZr%)r[r'rXr%)r_rRNr:)r`rTNr:)rarVNr:)rbr rcr")rdr+rer%)rfr rcr%)rgrRNr%)rhrTNr%)rirVNr%)rbr'rcr")rdr/rer%)rfr'rcr%)rjrrkr")rlrlNr%)rmrrkr%)rnr ror")rprpNr%)rqr ror%)rnr'ror")rqr'ror%)rrrDrsr")rtr+rur%)rvrDrsr%)rrr'rsr")rtr/rur%)rvr'rsr%)rwr rxr")ryr+rzr%)r{r rxr%)rwr'rxr")ryr/rzr%)r{r'rxr%)r|r r}r")r~r+rr%)rr r}r%)r|r'r}r")r~r/rr%)rr'r}r%)rr+rr%)rr'rr")rr+rr%)rrr rrr classmethodrr r r r r's rcCs&tj|||\}}d||j|f|fS)Nz%4d: (%02x) %s)rrr)rw0rrskipr r r disassemble_instruction3src Cstjtj|tjt}tt|d}|d}d}g}xRtd|D]D}||}|rf|d8}d|}nt|d||\}}|j ||}qDWt|d|d\}}|j ||S)Nr:rrz%4d: (64-bit upper word)) r castZc_char_pZPOINTERrintlenrangerappend) bpfstrZptrZnuminstrrr instr_listrrZ instr_strr r r disassemble_str7s    rcCs d|g}|t|7}tj|S)NzDisassemble of BPF program %s:)rrjoin)Z func_namerrr r r disassemble_progJs  rc"@seZdZejdejdejdejdejdej dej dej dej d ej d ejd ejd ejd ejdejdejddejddiZeddZed!ddZed"ddZeddZed#dd ZdS)$ MapDecoderZ_BoolcharZwchar_tz unsigned charZshortzunsigned shortrz unsigned intZlongz unsigned longz long longzunsigned long longfloatZdoublez long doubleZ__int128zunsigned __int128c Csy^t|tjrd}nHt|tjr&d}n6t|tjrR|j|jdt|jd}n |j|}Wnt k rzt|}YnX|S)Nstructunion[]) issubclassr StructureUnionZArray ctype2strZ_type_strZ_length_r)rtfield_type_namer r r get_ct_namebs    zMapDecoder.get_ct_nameFNcCs*|sdS|dk rd|||fSd||fS)Nz[%d,%d +%d bit]z [%d +%d] r )rrsizeZenabledZ bitoffsetr r r format_size_infoqs zMapDecoder.format_size_inforrcCsg}yx|jD]\}}t|tjp,t|tj}|j|} t||j} tj|} |j || | |} |r|j d|| | f||j ||d|| 7}|j d||fq|j d|| | |fqWWnt k rd} x|jD]}t |dkr0|\}}}|j|} |j || ||} |j d|| | ||fn`|\}}|j|} t||j} tj|} d}d} |j || | |} |j d|| | |f|| 7}| |7} qWYnX|S)Nz%s%s%s {z z%s} %s;z %s%s%s %s;rz %s%s%s %s:%d;)r rr rrr getattrrZsizeofrr print_ct_map ValueErrorr)rr indentrsizeinfo map_lines field_nameZ field_type is_structuredr Z field_offsetZ field_sizeZsizedescZ offset_bitsZfieldZ field_bitsr r r rysZ                   zMapDecoder.print_ct_mapcCsft|tjpt|tj}|j|}|rTd|g}||j|d|d7}|jd|nd||fg}|S)Nz %s {z )rz } %s;z %s %s;)rr rrr rr)rr rrrZ type_namerr r r print_map_ctypes    zMapDecoder.print_map_ctypecCsLd|||j|jfg}||j|jd|d7}||j|jd|d7}tj|S)Nz-Layout of BPF map %s (type %s, FD %d, ID %d):key)rvalue)Zmap_fdZmap_idrZKeyZLeafrr)rmap_namemap_objmap_typerrr r r decode_maps zMapDecoder.decode_map)FN)rrF)F)rrr r Zc_boolZc_charZc_wcharZc_ubyteZc_shortZc_ushortZc_intZc_uintZc_longZc_ulongZ c_longlongZ c_ulonglongZc_floatZc_doubleZ c_longdoubleZc_int64rr rr rrrr r r r r rOs2    3 rFcCst|}tj||||dS)N)r)rrr )rrrrZ map_type_namer r r r sr )N)F)osrZctypesr tablerrrrrrrrrrrrr r r r r s    u__pycache__/table.cpython-36.pyc000064400000131750152344707330012510 0ustar003 :)gB@s4ddlmZyddlmZWn ek r<ddlmZYnXddlmZddlZ ddl m Z ddl Z ddl Z ddlZddlZddlmZmZmZmZmZddlmZdd lmZdZd Zd Zd Zd ZdZdZdZ dZ!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/d Z0d!Z1d"Z2d#Z3d$Z4d%Z5ed&ed'ed(ed)ed*ed+ed,e d-e!d.e"d/e#d0e$d1e%d2e&d3e'd4e(d5e)d6e*d7e+d8e,d9e-d:e.d;e/de2d?e3d@e4dAe5dBiZ6dCa7dDZ8dEZ9dFdGZ:d~dHdIZ;dJdKZdPdQZ?dRdSZ@GdTdUdUeZAGdVdWdWeAZBGdXdYdYeBZCGdZd[d[eAZDGd\d]d]eDZEGd^d_d_eDZFGd`dadaZGGdbdcdceDZHGdddedeeDZIGdfdgdgeBZJGdhdidieJZKGdjdkdkeDZLGdldmdmeAZMGdndodoeAZNGdpdqdqeDZOGdrdsdseDZPGdtdudueDZQGdvdwdweDZRGdxdydyeBZSGdzd{d{eAZTGd|d}d}ZUdS))print_function)MutableMapping)strftimeN)reduce)lib _RAW_CB_TYPE _LOST_CB_TYPE_RINGBUF_CB_TYPEbcc_perf_buffer_opts)get_online_cpus)get_possible_cpus ZHASHZARRAYZ PROG_ARRAYZPERF_EVENT_ARRAYZ PERCPU_HASHZ PERCPU_ARRAYZ STACK_TRACEZ CGROUP_ARRAYZLRU_HASHZLRU_PERCPU_HASHZLPM_TRIEZ ARRAY_OF_MAPSZ HASH_OF_MAPSZDEVMAPZSOCKMAPZCPUMAPZXSKMAPZSOCKHASHZCGROUP_STORAGEZREUSEPORT_SOCKARRAYZPERCPU_CGROUP_STORAGEZQUEUEZSTACKZ SK_STORAGEZ DEVMAP_HASHZ STRUCT_OPSZRINGBUFZ INODE_STORAGEZ TASK_STORAGE(AicCs\d}d}x6||||dks*||dkr,P|d7}|d7}q W||krX|ddd}|S)Nrr*+)valval_maxwidthitextr0r0/usr/lib/python3.6/table.py_starscs  r7c Csg}d}x$tt|D]}||dkr|}qWd}d}xftt|D]V}|dkrD||krD|d}i}||d<t|d|d<t|||d<|j||}qDWtd||d} |r|d| |d<t| dS) Nrrrzinterval-startz interval-endcountz%Y-%m-%d %H:%M:%S)Ztsval_typedata)rangelenintappendrprint) valsr9section_bucketZ hist_listZmax_nonzero_idxr4indexprevZlist_objZ histogramr0r0r6_print_json_histos(  rDc Csd}d }d}x,t|D] \}}|dkr*|}||kr|}qW|dkrPd}d} t} nd}d} ttd } |dkrxt||xtd|dD]~}d|>d?} d|>d} | | kr| d8} ||} |r| rt| | | | | t| || fd }qt| | | | | t| || fqWdS) N@rr z# %-19s : count distributionz%10d -> %-10d : %-8d |%-*s|z- %-29s : count distributionz%20d -> %-20d : %-8d |%-*s|rFr/) enumerate stars_maxr=r?r;r7)r@r9strip_leading_zero log2_dist_maxidx_maxr2r4vheaderbodystarsZlowZhighr1r0r0r6_print_log2_hists<      rPc Csd}d}d}x,t|D] \}}|dkr*|}||kr|}qWd}d} t} |dkrZt||xdtd|dD]R}||} |r| rt| || | t| || fd}qjt| || | t| || fqjWdS)NrErrz# %-13s : count distributionz %-10d : %-8d |%-*s|Fr/)rGrHr?r;r7) r@r9rIrJrKr2r4rLrMrNrOr1r0r0r6_print_linear_hists,   rQc Cs"yt|Stk rdSXdS)Nz ) map_type_nameKeyError)ttyper0r0r6get_table_type_namesrUc Cstjtjtjtjtjtjtjtjtjtjtjtjtjtjtjtjtj tj tj tj tj tj dtj dtj d}t jd}g}tj|jj|j}d}x||krrtj|jj|j|j}t jd|}|jd}|jd} t jd| rd} |j| }yD|r |j|||jdt|jdfn|j||| fWn2tk rftd | tjd tjdYnX|d7}qWtd tj fd |iS) Nr)charZs8z unsigned charu8zu8 *zchar *ZshortZs16zunsigned shortu16r=Zs32enumz unsigned intu32Zlongz unsigned longz long longZs64zunsigned long longZu64Z__int128zunsigned __int128zvoid *z([^ ]+) ?\[([0-9]+)\]$rz (.*)#(.*)rzenum .*rYzGType: '%s' not recognized. Please define the data with ctypes manually.)filer,_fields_)!ctZc_charZc_ubyteZc_char_pZc_shortZc_ushortc_intc_uintZc_longZc_ulongZ c_longlongZ c_ulonglongZc_void_precompilerZbpf_perf_event_fieldsbpfmodule_nameZbpf_perf_event_fielddecodematchgroupr>r=rSr?sysstderrexittype Structure) Z event_mapZ ct_mappingZ array_typeZfields num_fieldsr4ZfieldmZ field_nameZ field_typer0r0r6_get_event_classs\        ( roc Ks8tj|j|}d}|tkr.t|||||}n|tkrJt|||||}n|tkrft|||||}n|t krt ||||||}n|t krt |||||f|}nz|t krt|||||f|}nZ|tkrt|||||}n>|tkrt|||||}n"|tkrt|||||}n|tkr6t|||||}n|tkrRt|||||}n|tkrnt|||||}n|tkrt|||||}n|tkrt|||||}nx|tkrt |||||}n\|t!krt"|||||}n@|t#ks|t$krt%||||}n|t&krt'||||||}|dkr4t(d||S)z|Table(bpf, map_id, map_fd, keytype, leaftype, **kwargs) Create a python object out of a reference to a bpf table handleNzUnknown table type %d))rbpf_table_type_idrcBPF_MAP_TYPE_HASH HashTableBPF_MAP_TYPE_ARRAYArrayBPF_MAP_TYPE_PROG_ARRAY ProgArrayBPF_MAP_TYPE_PERF_EVENT_ARRAYPerfEventArrayBPF_MAP_TYPE_PERCPU_HASH PerCpuHashBPF_MAP_TYPE_PERCPU_ARRAY PerCpuArrayBPF_MAP_TYPE_LPM_TRIELpmTrieBPF_MAP_TYPE_STACK_TRACE StackTraceBPF_MAP_TYPE_LRU_HASHLruHashBPF_MAP_TYPE_LRU_PERCPU_HASH LruPerCpuHashBPF_MAP_TYPE_CGROUP_ARRAY CgroupArrayBPF_MAP_TYPE_DEVMAPDevMapBPF_MAP_TYPE_CPUMAPCpuMapBPF_MAP_TYPE_XSKMAPXskMapBPF_MAP_TYPE_ARRAY_OF_MAPS MapInMapArrayBPF_MAP_TYPE_HASH_OF_MAPS MapInMapHashBPF_MAP_TYPE_QUEUEBPF_MAP_TYPE_STACK QueueStackBPF_MAP_TYPE_RINGBUFRingBuf Exception) rbmap_idmap_fdkeytypeleaftypenamekwargsrTtr0r0r6Table sR           rc@seZdZdDddZddZddZdd Zd d Zd d ZddZ ddZ ddZ ddZ ddZ ddZddZddZdEdd ZdFd!d"Zd#d$ZdGd%d&Zd'd(Zd)d*ZdHd,d-Zd.d/Zd0d1Zd2d3Zd4d5ZGd6d7d7eZd8d9Zd:d;ZdId>d?Z dJd@dAZ!dKdBdCZ"dS)L TableBaseNcCsn||_||_||_||_||_tj|jj|j|_tj |jj|j|_ i|_ ||_ t tj|jj|j|_dS)N)rbrrKeyLeafrrprcrTbpf_table_flags_idflags_cbsrdr=bpf_table_max_entries_id max_entries)selfrbrrrrrr0r0r6__init__?s zTableBase.__init__cCs|jS)N)r)rr0r0r6get_fdLszTableBase.get_fdcCsNtjtj|jd}tj|jj|j|t |tj |}|dkrHt d|j S)NrrzCould not printf key) r]create_string_buffersizeofrrZbpf_table_key_snprintfrbrcrr<byrefrvalue)rkeybufresr0r0r6 key_sprintfOs zTableBase.key_sprintfcCsNtjtj|jd}tj|jj|j|t |tj |}|dkrHt d|j S)NrrzCould not printf leaf) r]rrrrbpf_table_leaf_snprintfrbrcrr<rrr)rleafrrr0r0r6 leaf_sprintfWs zTableBase.leaf_sprintfcCs8|j}tj|jj|j|tj|}|dkr4td|S)NrzCould not scanf key) rrZbpf_table_key_sscanfrbrcrr]rr)rZkey_strrrr0r0r6 key_scanf_s  zTableBase.key_scanfcCs8|j}tj|jj|j|tj|}|dkr4td|S)NrzCould not scanf leaf) rrbpf_table_leaf_sscanfrbrcrr]rr)rleaf_strrrr0r0r6 leaf_scanfgs  zTableBase.leaf_scanfcCs4|j}tj|jtj|tj|}|dkr0t|S)Nr)rrbpf_lookup_elemrr]rrS)rrrrr0r0r6 __getitem__os zTableBase.__getitem__cCsDtj|jtj|tj|d}|dkr@tjtj}td|dS)NrzCould not update table: %s) rbpf_update_elemrr]rosstrerror get_errnor)rrrrerrstrr0r0r6 __setitem__vszTableBase.__setitem__cCs$tj|jtj|}|dkr tdS)Nr)rZbpf_delete_elemrr]rrS)rrrr0r0r6 __delitem__|szTableBase.__delitem__c cs6x0|D](}y||VWqtk r,YqXqWdS)N)rS)rrr0r0r6 itervaluess  zTableBase.itervaluesc cs:x4|D],}y|||fVWqtk r0YqXqWdS)N)rS)rrr0r0r6 iteritemss  zTableBase.iteritemscCsdd|jDS)NcSsg|]}|qSr0r0).0itemr0r0r6 sz#TableBase.items..)r)rr0r0r6itemsszTableBase.itemscCsdd|jDS)NcSsg|]}|qSr0r0)rrr0r0r6rsz$TableBase.values..)r)rr0r0r6valuesszTableBase.valuescCs x|jD]}|j|q WdS)N)keysr)rkr0r0r6clearszTableBase.clearFcCszd}}| r$| r$tjdddfS|s0|j}n|dksB||jkrJtd|rZ|j|}|rj|j|}tj|||fS)aAllocate keys and/or values arrays. Useful for in items_*_batch. Args: alloc_k (bool): True to allocate keys array, False otherwise. Default is False. alloc_v (bool): True to allocate values array, False otherwise. Default is False. count (int): number of elements in the array(s) to allocate. If count is None then it allocates the maximum number of elements i.e self.max_entries. Returns: tuple: (count, keys, values). Where count is ct.c_uint32, and keys and values an instance of ct.Array Raises: ValueError: If count is less than 1 or greater than self.max_entries. Nrrz Wrong count)r]c_uint32r ValueErrorrr)ralloc_kalloc_vr8rrr0r0r6_alloc_keys_valuess   zTableBase._alloc_keys_valuescCsvd}xF||gD]:}|rt|tjs&tt|}|dks@||jkrtdqW|rl|rlt|t|krltdtj|S)aCheck if the given keys or values have the right type and size. Args: keys (ct.Array): keys array to check values (ct.Array): values array to check Returns: ct.c_uint32 : the size of the array(s) Raises: ValueError: If length of arrays is less than 1 or greater than self.max_entries, or when both arrays length are different. TypeError: If the keys and values are not an instance of ct.Array rrzArray's length is wrongz(keys array length != values array length) isinstancer]rt TypeErrorr<rrr)rrrZarr_lenelemr0r0r6_sanity_check_keys_valuess   z#TableBase._sanity_check_keys_valuesccs(x"|jddD]\}}||fVqWdS)aLook up all the key-value pairs in the map. Args: None Yields: tuple: The tuple of (key,value) for every entries that have been looked up. Notes: lookup batch on a keys subset is not supported by the kernel. F)deleteN))_items_lookup_and_optionally_delete_batch)rrrLr0r0r6items_lookup_batchs zTableBase.items_lookup_batchcCsh|dk rP|j|d}tj|jtj|tj|}|dkrdtdtjtj nx|j D]}dSWdS)aDelete the key-value pairs related to the keys given as parameters. Note that if no key are given, it is faster to call lib.bpf_lookup_and_delete_batch than create keys array and then call lib.bpf_delete_batch on these keys. Args: ct_keys (ct.Array): keys array to delete. If an array of keys is given then it deletes all the related keys-values. If keys is None (default) then it deletes all entries. Yields: tuple: The tuple of (key,value) for every entries that have been deleted. Raises: Exception: If bpf syscall return value indicates an error. N)rrz#BPF_MAP_DELETE_BATCH has failed: %s) rrZbpf_delete_batchrr]rrrrritems_lookup_and_delete_batch)rct_keysct_cntr_r0r0r6items_delete_batchs  zTableBase.items_delete_batchcCsT|j||d}tj|jtj|tj|tj|}|dkrPtdtjtj dS)aqUpdate all the key-value pairs in the map provided. The arrays must be the same length, between 1 and the maximum number of entries. Args: ct_keys (ct.Array): keys array to update ct_values (ct.Array): values array to update Raises: Exception: If bpf syscall return value indicates an error. )rrrz#BPF_MAP_UPDATE_BATCH has failed: %sN) rrZbpf_update_batchrr]rrrrr)rr ct_valuesrrr0r0r6items_update_batch s  zTableBase.items_update_batchccs(x"|jddD]\}}||fVqWdS)a?Look up and delete all the key-value pairs in the map. Args: None Yields: tuple: The tuple of (key,value) for every entries that have been looked up and deleted. Notes: lookup and delete batch on a keys subset is not supported by the kernel. T)rN)r)rrrLr0r0r6r s z'TableBase.items_lookup_and_delete_batchTc cs4|dkrtj}d}n tj}d}|jddd\}}}tjd}}d} x|j| |_||j| rftj|ndtj|tj|tj |j | tj|tj |j | tj|} tj } | |j7} | dkr| t jkrtd|tj| f| dkrP| |jkrP|jdkrFPqFWx&td| D]} || || fVqWdS)aLook up and optionally delete all the key-value pairs in the map. Args: delete (bool) : look up and delete the key-value pairs when True, else just look up. Yields: tuple: The tuple of (key,value) for every entries that have been looked up and deleted. Raises: Exception: If bpf syscall return value indicates an error. Notes: lookup and delete batch on a keys subset is not supported by the kernel. TZBPF_MAP_LOOKUP_AND_DELETE_BATCHZBPF_MAP_LOOKUP_BATCH)rrrNz%s has failed: %s)rZbpf_lookup_and_delete_batchZbpf_lookup_batchrr]rrrrrrrrerrnoENOENTrrrr;) rrZ bpf_batchZbpf_cmdZ ct_buf_sizerrZ ct_out_batchrZtotalrZerrcoder4r0r0r6r/s<     z3TableBase._items_lookup_and_optionally_delete_batchcCs&x t|jD]}|j||<qWdS)N)listrr)rrr0r0r6zerofszTableBase.zerocCs tj|S)N)rIter)rr0r0r6__iter__nszTableBase.__iter__cCs|jS)N)r)rr0r0r6iterqszTableBase.itercCs|jS)N)r)rr0r0r6rrszTableBase.keysc@s,eZdZddZddZddZddZd S) zTableBase.ItercCs||_d|_dS)N)tabler)rrr0r0r6ruszTableBase.Iter.__init__cCs|S)Nr0)rr0r0r6rxszTableBase.Iter.__iter__cCs|jS)N)next)rr0r0r6__next__zszTableBase.Iter.__next__cCs|jj|j|_|jS)N)rrr)rr0r0r6r|szTableBase.Iter.nextN)__name__ __module__ __qualname__rrrrr0r0r0r6rtsrcCs^|j}|dkr0tj|jtj|tj|j}ntj|jtj|tj|}|dkrZt|S)Nr) rrZbpf_get_first_keyrr]rrZbpf_get_next_key StopIteration)rrZnext_keyrr0r0r6rs zTableBase.nextc Cs|jjdd}|jjdd}|dkrHt|jjdkrH|jjdd}xX|jD]L\}}t||} |rp|| } |j| dgt} || <t||} |j| | <qRWt|j } |r|| } x| D]} |j | qWdS)NrrZ__pad_1rr) rr\r<rgetattrgetlog2_index_maxrrrr>) rtmpbuckets bucket_fnbucket_sort_fnf1f2rrLbucketr@ZslotZ buckets_lstr0r0r6decode_c_structs     zTableBase.decode_c_structr Bucket ptrc Cst|jtjrfi}g}|j||||xr|D]2}||} |rL|||f} n||f} t| || q.Wn6dgt} x |jD]\} } | j| | j<qzWt| |dS)a.print_json_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, bucket_sort_fn=None): Prints a table as a json histogram. The table must be stored as log2. The val_type argument is optional, and is a column header. If the histogram has a secondary key, the dictionary will be split by secondary key If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is log2_index_max (65), which will accommodate any 64-bit integer in the histogram. rN) rrr]rlrrDrrr) rr9section_headersection_print_fnrrrrrr@rArrLr0r0r6print_json_hists  zTableBase.print_json_histc Cst|jtjrvi}g}|j||||x|D]B} || } |rTtd||| fntd|| ft| ||q.Wn8dgt} x |jD]\} } | j | | j <qWt| ||dS)aprint_log2_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None): Prints a table as a log2 histogram. The table must be stored as log2. The val_type argument is optional, and is a column header. If the histogram has a secondary key, multiple tables will print and section_header can be used as a header description for each. If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If the value of strip_leading_zero is not False, prints a histogram that is omitted leading zeros from the beginning. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is log2_index_max (65), which will accommodate any 64-bit integer in the histogram. z %s = %sz %s = %rrN) rrr]rlrr?rPrrr) rr9rrrrIrrrrr@rrLr0r0r6print_log2_hists  zTableBase.print_log2_histc Cst|jtjrvi}g}|j||||x|D]B} || } |rTtd||| fntd|| ft| ||q.Wnddgt} xL|jD]@\} } y| j | | j <Wqt k rt d| j tfYqXqWt| ||dS)aprint_linear_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None) Prints a table as a linear histogram. This is intended to span integer ranges, eg, from 0 to 100. The val_type argument is optional, and is a column header. If the histogram has a secondary key, multiple tables will print and section_header can be used as a header description for each. If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If the value of strip_leading_zero is not False, prints a histogram that is omitted leading zeros from the beginning. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is linear_index_max (1025), which is hoped to be sufficient for integer ranges spanned. z %s = %sz %s = %rrz#Index in print_linear_hist() of %d zexceeds max of %d.Nz5Index in print_linear_hist() of %d exceeds max of %d.) rrr]rlrr?rQlinear_index_maxrr IndexError) rr9rrrrIrrrrr@rrLr0r0r6print_linear_hists&  zTableBase.print_linear_hist)N)FFN)NN)N)T)rrNNN)rrNNNN)rrNNNN)#rrrrrrrrrrrrrrrrrrrrrrrrrrrrobjectrrrrrrr0r0r0r6r=sH   #   7  # &rcs$eZdZfddZddZZS)rrcstt|j||dS)N)superrrr)rargsr) __class__r0r6r"szHashTable.__init__cCsd}x|D] }|d7}q W|S)Nrrr0)rr4rr0r0r6__len__%s zHashTable.__len__)rrrrr __classcell__r0r0)rr6rr!s rrcseZdZfddZZS)rcstt|j||dS)N)rrr)rrr)rr0r6r+szLruHash.__init__)rrrrrr0r0)rr6r*srcspeZdZfddZddZddZfddZfd d Zfd d Zd dZ ddZ Gddde Z Z S) ArrayBasecstt|j||dS)N)rrr)rrr)rr0r6r/szArrayBase.__init__cCsVt|tr(|dkrt||}|j|}t|tjs||d@dkrtdx tD]}|j|||||q WdS)azopen_perf_buffers(callback) Opens a set of per-cpu ring buffer to receive custom perf event data from the bpf program. The callback will be invoked for each event submitted from the kernel, up to millions per second. Use page_cnt to change the size of the per-cpu ring buffer. The value must be a power of two and defaults to 8. rrz+Perf buffer page_cnt must be a power of twoN)rr _open_perf_buffer)rcallbackpage_cntlost_cb wakeup_eventsr4r0r0r6open_perf_buffers  zPerfEventArray.open_perf_bufferc sfdd}fdd}t|}r.t|n tjdt} t} d| _| _|| _tj || d|tj | } | svt dtj | } |j | ||j<| |jjt|f<|| f|j<d|j<dS) NcsPy||Wn:tk rJ}z|jtjkr6tn|WYdd}~XnXdS)N)IOErrorrEPIPErj)rr:sizee)rcpur0r6raw_cb_s  z1PerfEventArray._open_perf_buffer..raw_cb_csLy |Wn:tk rF}z|jtjkr2tn|WYdd}~XnXdS)N)r"rr#rj)rZlostr%)rr0r6lost_cb_s   z2PerfEventArray._open_perf_buffer..lost_cb_rzCould not open perf bufferr/r/)rr r]rr pidr&r rZbpf_open_perf_buffer_optsrrZperf_reader_fdrrrbrrrr) rr&rrrr r'r(fnZlost_fnZoptsreaderr r0)rr&rr6rs   z PerfEventArray._open_perf_buffercCsBtj||d|}|dkr td|j|||j|<||j|<dS)Nrrzbpf_open_perf_event failedr/)rZbpf_open_perf_eventrrrr)rr&typconfigr r0r0r6_open_perf_events zPerfEventArray._open_perf_eventcCs"xtD]}|j|||qWdS)zopen_perf_event(typ, config) Configures the table such that calls from the bpf program to table.perf_read(CUR_CPU_IDENTIFIER) will return the hardware counter denoted by event ev on the local cpu. N)r r.)rr,r-r4r0r0r6open_perf_events zPerfEventArray.open_perf_event)rNr) rrrrr rrr!rr.r/rr0r0)rr6rxs   "rxcsTeZdZfddZfddZddZfddZd d Zd d Zd dZ Z S)rzcs|jdd|_tt|j|||j|_tt|_ t j |jd|_ |j dkr`|j|j |_n@|jt j kr|t j|j |_n$|jt jkrt j|j |_ntddS)NreducerrrzLeaf must be aligned to 8 bytes)popr0rrzrrsLeafr<r total_cpur]r alignmentr_c_uint64r^c_int64r)rrr)rr0r6rs    zPerCpuHash.__init__csTtt|j|}|jdkr |}n0|j|j}x td|jD]}||||<q.ringbuf_cb_rN)r rbZ_open_ring_bufferrr)rrrHrIr*r0)rr6open_ring_buffers zRingBuf.open_ring_buffer)N) rrrrZ_RingBuf__delitemr rrrJrr0r0)rr6rs   rc@sReZdZdZddZddZddZdd d Zd d Zd dZ ddZ ddZ dS)rrcCs\||_||_||_||_tj|jj|j|_tj|jj|j|_ t tj |jj|j|_ dS)N) rbrrrrrprcrTrrr=rr)rrbrrrr0r0r6rs zQueueStack.__init__cCsNtjtj|jd}tj|jj|j|t |tj |}|dkrHt d|j S)NrrzCould not printf leaf) r]rrrrrrbrcrr<rrr)rrrrr0r0r6rs zQueueStack.leaf_sprintfcCs8|j}tj|jj|j|tj|}|dkr4td|S)NrzCould not scanf leaf) rrrrbrcrr]rr)rrrrr0r0r6rs  zQueueStack.leaf_scanfrcCs>tj|jdtj||}|dkr:tjtj}td|dS)NrzCould not push to table: %s) rrrr]rrrrr)rrrrrr0r0r6pushszQueueStack.pushcCs2|j}tj|jdtj|}|dkr.td|S)NrzCould not pop from table)rrZbpf_lookup_and_deleterr]rrS)rrrr0r0r6r1$s zQueueStack.popcCs2|j}tj|jdtj|}|dkr.td|S)NrzCould not peek table)rrrrr]rrS)rrrr0r0r6peek+s zQueueStack.peekc cs@|j}x4|r:y|jV|d8}Wqtk r6dSXqWdS)Nr)rr1rS)rZcntr0r0r6r2s  zQueueStack.itervaluescCsdd|jDS)NcSsg|]}|qSr0r0)rrr0r0r6r=sz%QueueStack.values..)r)rr0r0r6r<szQueueStack.valuesN)r) rrrZ BPF_EXISTrrrrKr1rLrrr0r0r0r6rs   r)N)VZ __future__rcollections.abcr ImportError collectionsZtimerZctypesr] functoolsrrrr`rhZlibbccrrr r r Zutilsr r rqrsrurwryr{rrrrr}rrrZBPF_MAP_TYPE_SOCKMAPrrZBPF_MAP_TYPE_SOCKHASHZBPF_MAP_TYPE_CGROUP_STORAGEZ BPF_MAP_TYPE_REUSEPORT_SOCKARRAYZ"BPF_MAP_TYPE_PERCPU_CGROUP_STORAGErrZBPF_MAP_TYPE_SK_STORAGEZBPF_MAP_TYPE_DEVMAP_HASHZBPF_MAP_TYPE_STRUCT_OPSrZBPF_MAP_TYPE_INODE_STORAGEZBPF_MAP_TYPE_TASK_STORAGErRrHrrr7rDrPrQrUrorrrrrrrtrvr rrxrzrr|r~rrrrrrrrr0r0r0r6s      &;0g 8 l4849__pycache__/usdt.cpython-36.opt-1.pyc000064400000017174152344707330013342 0ustar003 :)g5$@sddlmZddlZddlZddlmZmZmZm Z m Z m Z Gddde Z GdddeZGd d d eZGd d d eZGd ddeZdS))print_functionN)lib_USDT_CB_USDT_PROBE_CBbcc_usdt_locationbcc_usdt_argumentBCC_USDT_ARGUMENT_FLAGSc@s eZdZdS) USDTExceptionN)__name__ __module__ __qualname__rr/usr/lib/python3.6/usdt.pyr sr c@s,eZdZddZddZddZddZd S) USDTProbeArgumentcCs|jdk|_t|j|_|j|_|jtj@dkr8|j|_|jtj@dkrP|j|_|jtj @dkrh|j |_ |jtj @dkr|j |_ |jtj @dkr|j|_|jtj@dkr|j|_dS)Nr)sizesignedabsvalidr CONSTANTconstant DEREF_OFFSET deref_offset DEREF_IDENT deref_identBASE_REGISTER_NAMEbase_register_nameINDEX_REGISTER_NAMEindex_register_nameSCALEscale)selfZargumentrrr__init__s  zUSDTProbeArgument.__init__cCsd|j|jrdndfS)Nz %d %s byteszsigned Zunsigned)rr)r!rrr _size_prefix+szUSDTProbeArgument._size_prefixcCsB|jtj@dkrd|jS|jtj@dkr8d|jjS|jtj@dkr|jtj@dkr|jtj@dkrd|j j}|jtj @dkr|d|j 7}nd}|j dkrdnd}d |jj|t |j |fS|jtj@dkr8|jtj@dkr8|jtj@dkr8|jd kr8|j dkrdnd}d |jj|t |j fSd |jS) Nrz%dz%sz + %sz * %d+-z *(%s %s %d%s)Zipz *(&%s %s %d)z&unrecognized argument format, flags %d)rr rrrrdecoderrrrr rrrr)r!Z index_offsetZsignrrr_format/s,    zUSDTProbeArgument._formatcCsd|j|jfS)Nz%s @ %s)r#r()r!rrr__str__MszUSDTProbeArgument.__str__N)r r r r"r#r(r)rrrrrsrc@s$eZdZddZddZddZdS)USDTProbeLocationcCs(||_||_|j|_|j|_|j|_dS)N)probeindex num_argumentsaddressbin_path)r!r+r,locationrrrr"Qs zUSDTProbeLocation.__init__cCsd|jj|jfS)Nz%s 0x%x)r/r'r.)r!rrrr)XszUSDTProbeLocation.__str__cCsPt}tj|jj|jj|jj|j|tj |}|dkrHt d||jft |S)Nrz.error retrieving probe argument %d location %d) rrZbcc_usdt_get_argumentr+contextprovidernamer,ctbyrefr r)r!r,argresrrr get_argument[szUSDTProbeLocation.get_argumentN)r r r r"r)r8rrrrr*Psr*c@s,eZdZddZddZddZddZd S) USDTProbecCs:||_|j|_|j|_|j|_|j|_|j|_|j|_dS)N)r1r2r3r/ semaphoreZ num_locationsr-)r!r1r+rrrr"gszUSDTProbe.__init__cCsd|jj|jj|jfS)Nz%s:%s [sema 0x%x])r2r'r3r:)r!rrrr)pszUSDTProbe.__str__cCsd|jj|jjfS)Nz%s:%s)r2r'r3)r!rrr short_nametszUSDTProbe.short_namecCsDt}tj|j|j|j|tj|}|dkr8td|t |||S)Nrz"error retrieving probe location %d) rrZbcc_usdt_get_locationr1r2r3r4r5r r*)r!r,locr7rrr get_locationws  zUSDTProbe.get_locationN)r r r r"r)r;r=rrrrr9fs r9c@s^eZdZdddZddZddZdd Zd d Zd d ZddZ ddZ ddZ ddZ dS)USDTNcCs|rX|dkrX||_|r,tj||jd|_ntj|tjd|_|jdkrtd|n<|r||_tj |jd|_|jdkrtd|ntddS)Nrasciirz USDT failed to instrument PID %dz!USDT failed to instrument path %sz/either a pid or a binary path must be specified) pidrZbcc_usdt_new_frompidencoder1r4Zc_char_pr pathZbcc_usdt_new_frompath)r!rArCrrrr"s   z USDT.__init__cCstj|jdS)N)rZbcc_usdt_closer1)r!rrr__del__sz USDT.__del__cCsz|jdd}t|dkr6tj|j|jd|jd}n,|\}}tj|j|jd|jd|jd}|dkrvtd|dS)N:rr?ra.Failed to enable USDT probe '%s': the specified pid might not contain the given language's runtime, or the runtime was not built with the required USDT probes. Look for a configure flag similar to --with-dtrace or --enable-dtrace. To check which probes are present in the process, use the tplist tool. )splitlenrZbcc_usdt_enable_prober1rBZ%bcc_usdt_enable_fully_specified_prober )r!r+fn_name probe_partsret provider_name probe_namerrr enable_probes   zUSDT.enable_probecCsPy|j||Wn:tk rJ}zt|tjdtjdWYdd}~XnXdS)N)filer)rMr printsysstderrexit)r!r+rHerrrenable_probe_or_bails zUSDT.enable_probe_or_bailcCs|jS)N)r1)r!rrr get_contextszUSDT.get_contextcCs,tjd}tj|j|d<tj|djS)Nrr)r4Zc_void_pr1rZbcc_usdt_genargsr')r!Z ctx_arrayrrrget_texts z USDT.get_textcCs`|jdd}t|dkr2tj|j|jd|jS|\}}tj|j|jd|jd|jSdS)NrErr?)rFrGrZbcc_usdt_get_probe_argctyper1rBr'Z+bcc_usdt_get_fully_specified_probe_argctype)r!rLZ arg_indexrIrKr+rrrget_probe_arg_ctypes  zUSDT.get_probe_arg_ctypecs(gfdd}tjjt|S)Ncsjtj|jdS)N)appendr9r1contents)r+)probesr!rr _add_probesz)USDT.enumerate_probes.._add_probe)rZbcc_usdt_foreachr1r)r!r[r)rZr!renumerate_probesszUSDT.enumerate_probescCsD|j}x6|D].\}}}}|r"d}|j|j|j||dqWdS)Nr)r3rHaddrrAr@)enumerate_active_probesZ attach_uprober')r!ZbpfZattach_usdt_ignore_pidrZbinpathrHr]rArrrattach_uprobess zUSDT.attach_uprobescs&gfdd}tj|jt|S)Ncsj||||fdS)N)rX)r_rHr]rA)rZrrr[sz0USDT.enumerate_active_probes.._add_probe)rZbcc_usdt_foreach_uprober1r)r!r[r)rZrr^s zUSDT.enumerate_active_probes)NN) r r r r"rDrMrTrUrVrWr\r`r^rrrrr>s   r>)Z __future__rZctypesr4rPZlibbccrrrrrr Exceptionr objectrr*r9r>rrrrs  7__pycache__/libbcc.cpython-36.pyc000064400000020047152344707330012633 0ustar003 :)g8 @s2 ddlZejdddZddlmZejej_ej ej ej ej ej ej ej gej_ejej_ej ej ej ej ej ej ej gej_ej ej_dej_dej_ejgej_ej ej_ejgej_ej ej_ejgej_ejej_ejgej_ej ej_ejejgej_ejej_ejej gej_ejej_ejej gej_ejej_ejej gej_ej ej_ejej gej_ej ej_ejejgej_ejej_ejejgej_ej ej_ejejgej_ej ej_ejej gej_ej ej _ejej gej _ej ej!_ejejej ejejgej!_ej ej"_ejejej ejejgej"_ej ej#_ejejej ejgej#_ej ej$_ejejej ejgej$_ejej%_ejej gej%_ej ej&_ejej ejgej&_ej ej'_ej ejejgej'_ej ej(_ej ejej gej(_ej ej)_ej ejejgej)_ej ej*_ej ejejejgej*_ej ej+_ej ejgej+_ej ej,_ej ejejgej,_ej ej-_ej ejejej ej.gej-_ej ej/_ej ej ej.ej ej.ejejejgej/_ej ej0_ej ej ej.ej ej.ejejejgej0_ej ej1_ej gej1_ej ej2_ej ej gej2_ej ej3_ejej ej ejejej ej ej ej ej ej ej g ej3_ej4dej5ejej Z6ej4dej5ejZ7ej ej8_ej ej ej ej ejej gej8_ej ej9_ej gej9_ej ej:_ej ej ej ej ejej gej:_ej ej;_ej gej;_ej ej<_ej ej ej gej<_ej ej=_ej ej gej=_ej ej>_ej ej gej>_ej ej?_ej gej?_ej ej@_ej gej@_ej ejA_ej ej ej ej gejA_Bej ejC_ej ej ej gejC_Bej ejD_dejD_ej ejE_ej ej gejE_ejejF_e6e7ej5ej ej ej gejF_GdddejGZHejejI_e6e7ej5ej ej eHgejI_ej ejJ_ej ejej ej gejJ_ej ejK_ej ej ejej gejK_ej ejL_ej ej ejgejL_dejM_ejgejM_eNejO_ejgejO_ej ejP_ej ej ej gejP_ej ejQ_ej ej ej ejejej ej ej gejQ_Bej ejR_ejSej ej ej ej gejR_Bej ejT_ej gejT_Bej4ej ejejej ZUejejV_ej eUejgejV_dejW_ejgejW_ej ejX_ejej eUejgejX_ej ejY_ejej gejY_ej ejZ_ejgejZ_Gd d d ejGZ[Gd d d ej\Z]Gd ddejGZ^GdddejGZ_ej ej`eja_ej ej geja_dejb_ejgejb_ej ej`ejc_ej gejc_ej ejd_ej ej ejej ej e_ej e[gejd_ej4ej ej ejZeej ejf_ej eegejf_ejejg_ej ej e_gejg_ejejh_ejej gejh_ejeji_deji_dejj_ejgejj_ej ejk_ejej gejk_ej ejl_ejej e^ej e[gejl_ejejm_ej e[gejm_ej ejn_ejejej e[gejn_ej ejo_ejejej e[gejo_ej ejp_ejej ej ej ejgejp_dejq_ejgejq_ej ejr_dejr_ejejs_ej ej gejs_ejejt_ej gejt_deju_ejgeju_ej ejv_ejej ej gejv_ej ejw_ejej ej ej gejw_ej ejx_ej ejej gejx_ej ejy_ejej ej gejy_ej ejz_ejej ej ej gejz_GdddejGZ{GdddejGZ|Gddde}Z~GdddejGZej4dej e{Zdej_ejegej_ej ej_ejej ej ej ej e|gej_ej ej_ejej ej ej ej ej egej_ej4dej ej ejej Zdej_ejegej_dS)Nz libbcc.so.0T)Z use_errno)Perfc@s(eZdZdejfdejfdejfgZdS)bcc_perf_buffer_optspidZcpuZ wakeup_eventsN)__name__ __module__ __qualname__ctc_int_fields_r r /usr/lib/python3.6/libbcc.pyrsrc@s6eZdZdejfdejfdejejfdejfgZdS) bcc_symbolnameZ demangle_namemoduleoffsetN) rrrr c_char_pPOINTERc_char c_ulonglongr r r r r rsrc@s eZdZdejfdejfgZdS)bcc_ip_offset_unionrZipN)rrrr Zc_uint64r r r r r rsrc@s*eZdZdejfdejdfdefgZdS)bcc_stacktrace_build_idZstatusZbuild_iduN)rrrr c_uint32Zc_ubyterr r r r r rs rc@s0eZdZdejfdejfdejfdejfgZdS)bcc_symbol_optionZuse_debug_fileZcheck_debug_file_crcZlazy_symbolizeZuse_symbol_typeN)rrrr r c_uintr r r r r rsrc@s@eZdZdejfdejfdejfdejfdejfdejfgZdS)bcc_usdtZproviderrbin_pathZ semaphoreZ num_locationsZ num_argumentsN)rrrr rrr r r r r r r"s rc@s eZdZdejfdejfgZdS)bcc_usdt_locationZaddressrN)rrrr rrr r r r r r,src@s(eZdZdZdZdZdZdZdZdZ dS) BCC_USDT_ARGUMENT_FLAGSrr N) rrrZNONEZCONSTANTZ DEREF_OFFSETZ DEREF_IDENTZBASE_REGISTER_NAMEZINDEX_REGISTER_NAMEZSCALEr r r r r 2sr c @sPeZdZdejfdejfdejfdejfdejfdejfdejfdejfgZd S) bcc_usdt_argumentsizeZvalidZconstantZ deref_offsetZ deref_identZbase_register_nameZindex_register_nameZscaleN)rrrr r Z c_longlongrr r r r r r&;sr&)Zctypesr ZCDLLlibZperfrZc_void_pZbpf_module_create_cZrestyperrrr Zc_boolZargtypesZbpf_module_create_c_from_stringZbpf_module_rw_engine_enabledZbpf_module_destroyZbpf_module_licenseZbpf_module_kern_versionrZbpf_num_functionsZbpf_function_nameZbpf_function_startZc_size_tZbpf_function_sizeZ bpf_table_idZ bpf_table_fdZbpf_table_type_idZbpf_table_max_entries_idZbpf_table_flags_idZbpf_table_key_descZbpf_table_leaf_descZbpf_table_key_snprintfZbpf_table_leaf_snprintfZbpf_table_key_sscanfZbpf_table_leaf_sscanfZbpf_perf_event_fieldsZbpf_perf_event_fieldZbpf_get_next_keyZbpf_get_first_keyZbpf_lookup_elemZbpf_update_elemZbpf_delete_elemZbpf_delete_batchZbpf_update_batchrZbpf_lookup_batchZbpf_lookup_and_delete_batchZbpf_open_raw_sockZbpf_attach_socketZ bcc_func_loadZ CFUNCTYPEZ py_objectZ _RAW_CB_TYPEZ _LOST_CB_TYPEZbpf_attach_kprobeZbpf_detach_kprobeZbpf_attach_uprobeZbpf_detach_uprobeZbpf_attach_tracepointZbpf_detach_tracepointZbpf_attach_raw_tracepointZbpf_attach_kfuncZbpf_attach_lsmZbpf_prog_attachZargtypeZbpf_prog_detach2Zbpf_has_kernel_btfZkernel_struct_has_fieldZbpf_open_perf_bufferZ StructurerZbpf_open_perf_buffer_optsZbpf_open_perf_eventZperf_reader_pollZperf_reader_consumeZperf_reader_freeintZperf_reader_fdZbpf_attach_xdpZbpf_attach_perf_eventZbpf_attach_perf_event_rawZperf_event_attrZbpf_close_perf_event_fdZ_RINGBUF_CB_TYPEZbpf_new_ringbufZbpf_free_ringbufZbpf_add_ringbufZbpf_poll_ringbufZbpf_consume_ringbufrZUnionrrrrZbcc_procutils_which_soZbcc_procutils_freeZbcc_procutils_languageZbcc_resolve_symnameZ _SYM_CB_TYPEZbcc_foreach_function_symbolZbcc_symcache_newZbcc_free_symcacheZbcc_buildsymcache_newZbcc_free_buildsymcacheZbcc_buildsymcache_add_moduleZbcc_buildsymcache_resolveZbcc_symbol_free_demangle_nameZbcc_symcache_resolveZ bcc_symcache_resolve_no_demangleZbcc_symcache_resolve_nameZbcc_symcache_refreshZbcc_free_memoryZbcc_usdt_new_frompidZbcc_usdt_new_frompathZbcc_usdt_closeZbcc_usdt_enable_probeZ%bcc_usdt_enable_fully_specified_probeZbcc_usdt_genargsZbcc_usdt_get_probe_argctypeZ+bcc_usdt_get_fully_specified_probe_argctyperrobjectr r&Z_USDT_CBZbcc_usdt_foreachZbcc_usdt_get_locationZbcc_usdt_get_argumentZ_USDT_PROBE_CBZbcc_usdt_foreach_uprober r r r s                                           (                                      (                            __pycache__/usdt.cpython-36.pyc000064400000017174152344707330012403 0ustar003 :)g5$@sddlmZddlZddlZddlmZmZmZm Z m Z m Z Gddde Z GdddeZGd d d eZGd d d eZGd ddeZdS))print_functionN)lib_USDT_CB_USDT_PROBE_CBbcc_usdt_locationbcc_usdt_argumentBCC_USDT_ARGUMENT_FLAGSc@s eZdZdS) USDTExceptionN)__name__ __module__ __qualname__rr/usr/lib/python3.6/usdt.pyr sr c@s,eZdZddZddZddZddZd S) USDTProbeArgumentcCs|jdk|_t|j|_|j|_|jtj@dkr8|j|_|jtj@dkrP|j|_|jtj @dkrh|j |_ |jtj @dkr|j |_ |jtj @dkr|j|_|jtj@dkr|j|_dS)Nr)sizesignedabsvalidr CONSTANTconstant DEREF_OFFSET deref_offset DEREF_IDENT deref_identBASE_REGISTER_NAMEbase_register_nameINDEX_REGISTER_NAMEindex_register_nameSCALEscale)selfZargumentrrr__init__s  zUSDTProbeArgument.__init__cCsd|j|jrdndfS)Nz %d %s byteszsigned Zunsigned)rr)r!rrr _size_prefix+szUSDTProbeArgument._size_prefixcCsB|jtj@dkrd|jS|jtj@dkr8d|jjS|jtj@dkr|jtj@dkr|jtj@dkrd|j j}|jtj @dkr|d|j 7}nd}|j dkrdnd}d |jj|t |j |fS|jtj@dkr8|jtj@dkr8|jtj@dkr8|jd kr8|j dkrdnd}d |jj|t |j fSd |jS) Nrz%dz%sz + %sz * %d+-z *(%s %s %d%s)Zipz *(&%s %s %d)z&unrecognized argument format, flags %d)rr rrrrdecoderrrrr rrrr)r!Z index_offsetZsignrrr_format/s,    zUSDTProbeArgument._formatcCsd|j|jfS)Nz%s @ %s)r#r()r!rrr__str__MszUSDTProbeArgument.__str__N)r r r r"r#r(r)rrrrrsrc@s$eZdZddZddZddZdS)USDTProbeLocationcCs(||_||_|j|_|j|_|j|_dS)N)probeindex num_argumentsaddressbin_path)r!r+r,locationrrrr"Qs zUSDTProbeLocation.__init__cCsd|jj|jfS)Nz%s 0x%x)r/r'r.)r!rrrr)XszUSDTProbeLocation.__str__cCsPt}tj|jj|jj|jj|j|tj |}|dkrHt d||jft |S)Nrz.error retrieving probe argument %d location %d) rrZbcc_usdt_get_argumentr+contextprovidernamer,ctbyrefr r)r!r,argresrrr get_argument[szUSDTProbeLocation.get_argumentN)r r r r"r)r8rrrrr*Psr*c@s,eZdZddZddZddZddZd S) USDTProbecCs:||_|j|_|j|_|j|_|j|_|j|_|j|_dS)N)r1r2r3r/ semaphoreZ num_locationsr-)r!r1r+rrrr"gszUSDTProbe.__init__cCsd|jj|jj|jfS)Nz%s:%s [sema 0x%x])r2r'r3r:)r!rrrr)pszUSDTProbe.__str__cCsd|jj|jjfS)Nz%s:%s)r2r'r3)r!rrr short_nametszUSDTProbe.short_namecCsDt}tj|j|j|j|tj|}|dkr8td|t |||S)Nrz"error retrieving probe location %d) rrZbcc_usdt_get_locationr1r2r3r4r5r r*)r!r,locr7rrr get_locationws  zUSDTProbe.get_locationN)r r r r"r)r;r=rrrrr9fs r9c@s^eZdZdddZddZddZdd Zd d Zd d ZddZ ddZ ddZ ddZ dS)USDTNcCs|rX|dkrX||_|r,tj||jd|_ntj|tjd|_|jdkrtd|n<|r||_tj |jd|_|jdkrtd|ntddS)Nrasciirz USDT failed to instrument PID %dz!USDT failed to instrument path %sz/either a pid or a binary path must be specified) pidrZbcc_usdt_new_frompidencoder1r4Zc_char_pr pathZbcc_usdt_new_frompath)r!rArCrrrr"s   z USDT.__init__cCstj|jdS)N)rZbcc_usdt_closer1)r!rrr__del__sz USDT.__del__cCsz|jdd}t|dkr6tj|j|jd|jd}n,|\}}tj|j|jd|jd|jd}|dkrvtd|dS)N:rr?ra.Failed to enable USDT probe '%s': the specified pid might not contain the given language's runtime, or the runtime was not built with the required USDT probes. Look for a configure flag similar to --with-dtrace or --enable-dtrace. To check which probes are present in the process, use the tplist tool. )splitlenrZbcc_usdt_enable_prober1rBZ%bcc_usdt_enable_fully_specified_prober )r!r+fn_name probe_partsret provider_name probe_namerrr enable_probes   zUSDT.enable_probecCsPy|j||Wn:tk rJ}zt|tjdtjdWYdd}~XnXdS)N)filer)rMr printsysstderrexit)r!r+rHerrrenable_probe_or_bails zUSDT.enable_probe_or_bailcCs|jS)N)r1)r!rrr get_contextszUSDT.get_contextcCs,tjd}tj|j|d<tj|djS)Nrr)r4Zc_void_pr1rZbcc_usdt_genargsr')r!Z ctx_arrayrrrget_texts z USDT.get_textcCs`|jdd}t|dkr2tj|j|jd|jS|\}}tj|j|jd|jd|jSdS)NrErr?)rFrGrZbcc_usdt_get_probe_argctyper1rBr'Z+bcc_usdt_get_fully_specified_probe_argctype)r!rLZ arg_indexrIrKr+rrrget_probe_arg_ctypes  zUSDT.get_probe_arg_ctypecs(gfdd}tjjt|S)Ncsjtj|jdS)N)appendr9r1contents)r+)probesr!rr _add_probesz)USDT.enumerate_probes.._add_probe)rZbcc_usdt_foreachr1r)r!r[r)rZr!renumerate_probesszUSDT.enumerate_probescCsD|j}x6|D].\}}}}|r"d}|j|j|j||dqWdS)Nr)r3rHaddrrAr@)enumerate_active_probesZ attach_uprober')r!ZbpfZattach_usdt_ignore_pidrZbinpathrHr]rArrrattach_uprobess zUSDT.attach_uprobescs&gfdd}tj|jt|S)Ncsj||||fdS)N)rX)r_rHr]rA)rZrrr[sz0USDT.enumerate_active_probes.._add_probe)rZbcc_usdt_foreach_uprober1r)r!r[r)rZrr^s zUSDT.enumerate_active_probes)NN) r r r r"rDrMrTrUrVrWr\r`r^rrrrr>s   r>)Z __future__rZctypesr4rPZlibbccrrrrrr Exceptionr objectrr*r9r>rrrrs  7__pycache__/syscall.cpython-36.pyc000064400000021072152344707330013066 0ustar003 :)g%P@s dZddlZddlZddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;dd?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzd{d|d}d~ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdROZdSdTZyNejdUdVgejdWZejdXdYdYZe e eej jdXZWn@e k rZ z"ejdZkrn e d[WYddZ [ XnXd\d]ZdS(^zRsyscall.py contains functions useful for mapping between syscall names and numbersNsreadswritesopensclosesstatsfstatslstatspollslseeksmmapsmprotectsmunmapsbrks rt_sigactionsrt_sigprocmasks rt_sigreturnsioctlspread64spwrite64sreadvswritevsaccessspipesselects sched_yieldsmremapsmsyncsmincoresmadvisesshmgetsshmatsshmctlsdupsdup2spauses nanosleeps getitimersalarms setitimersgetpidssendfilessocketsconnectsacceptssendtosrecvfromssendmsgsrecvmsgsshutdownsbindslistens getsocknames getpeernames socketpairs setsockopts getsockoptsclonesforksvforksexecvesexitswait4skillsunamessemgetssemopssemctlsshmdtsmsggetsmsgsndsmsgrcvsmsgctlsfcntlsflocksfsyncs fdatasyncstruncates ftruncatesgetdentssgetcwdschdirsfchdirsrenamesmkdirsrmdirscreatslinksunlinkssymlinksreadlinkschmodsfchmodschownsfchownslchownsumasks gettimeofdays getrlimits getrusagessysinfostimessptracesgetuidssyslogsgetgidssetuidssetgidsgeteuidsgetegidssetpgidsgetppidsgetpgrpssetsidssetreuidssetregids getgroupss setgroupss setresuids getresuids setresgids getresgidsgetpgidssetfsuidssetfsgidsgetsidscapgetscapsets rt_sigpendingsrt_sigtimedwaitsrt_sigqueueinfos rt_sigsuspends sigaltstacksutimesmknodsuselibs personalitysustatsstatfssfstatfsssysfss getprioritys setpriorityssched_setparamssched_getparamssched_setschedulerssched_getschedulerssched_get_priority_maxssched_get_priority_minssched_rr_get_intervalsmlocksmunlocksmlockalls munlockallsvhangups modify_ldts pivot_roots_sysctlsprctls arch_prctlsadjtimexs setrlimitschrootssyncsaccts settimeofdaysmountsumount2sswaponsswapoffsreboots sethostnames setdomainnamesioplsioperms create_modules init_modules delete_modulesget_kernel_symss query_modulesquotactls nfsservctlsgetpmsgsputpmsgs afs_syscallstuxcallssecuritysgettids readaheadssetxattrs lsetxattrs fsetxattrsgetxattrs lgetxattrs fgetxattrs listxattrs llistxattrs flistxattrs removexattrs lremovexattrs fremovexattrstkillstimesfutexssched_setaffinityssched_getaffinitysset_thread_areasio_setups io_destroys io_geteventss io_submits io_cancelsget_thread_areaslookup_dcookies epoll_creates epoll_ctl_oldsepoll_wait_oldsremap_file_pagess getdents64sset_tid_addresssrestart_syscalls semtimedops fadvise64s timer_creates timer_settimes timer_gettimestimer_getoverruns timer_deletes clock_settimes clock_gettimes clock_getressclock_nanosleeps exit_groups epoll_waits epoll_ctlstgkillsutimessvserversmbinds set_mempolicys get_mempolicysmq_opens mq_unlinks mq_timedsendsmq_timedreceives mq_notifys mq_getsetattrs kexec_loadswaitidsadd_keys request_keyskeyctls ioprio_sets ioprio_gets inotify_initsinotify_add_watchsinotify_rm_watchs migrate_pagessopenatsmkdiratsmknodatsfchownats futimesats newfstatatsunlinkatsrenameatslinkats symlinkats readlinkatsfchmodats faccessatspselect6sppollsunsharesset_robust_listsget_robust_listssplicesteessync_file_rangesvmsplices move_pagess utimensats epoll_pwaitssignalfdstimerfd_createseventfds fallocatestimerfd_settimestimerfd_gettimesaccept4s signalfd4seventfd2s epoll_create1sdup3spipe2s inotify_init1spreadvspwritevsrt_tgsigqueueinfosperf_event_opensrecvmmsgs fanotify_inits fanotify_marks prlimit64sname_to_handle_atsopen_by_handle_ats clock_adjtimessyncfsssendmmsgssetnssgetcpusprocess_vm_readvsprocess_vm_writevskcmps finit_modules sched_setattrs sched_getattrs renameat2sseccomps getrandoms memfd_createskexec_file_loadsbpfsexecveats userfaultfds membarriersmlock2scopy_file_rangespreadv2spwritev2s pkey_mprotects pkey_allocs pkey_freesstatxs io_pgeteventssrseq(Or  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~iiiiiiiii i i i i iiiiiiiiiiiiiiiiiii i!i"i#i$i%i&i'i(i)i*i+i,i-i.i/i0i1i2i3i4i5i6i7i8i9i:i;i<i=i>i?i@iAiBiCiDiEiFiGiHiIiJiKiLiMiNcCs |j}t|d|djfS)Nrr)splitintstrip)linepartsr/usr/lib/python3.6/syscall.py_parse_syscalltsr Z ausyscallz--dump)stderr rZx86_64zausyscall: command not foundcCstj|d|S)z:Return the syscall name for the particular syscall number.s [unknown: %d])syscallsget)Z syscall_numrrr syscall_namesr)__doc__ subprocessplatformr r Z check_outputZSTDOUToutrdictmapr Exceptionemachinerrrrrs  __pycache__/__init__.cpython-36.pyc000064400000152240152344707330013155 0ustar003 :)gh @sddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z mZmZmZmZddlmZmZmZmZmZddlmZddlmZmZmZmZmZddl m!Z!dd l"m#Z#m$Z$dd l%m&Z&m'Z'ye(Wne)k re*Z(YnXd Z+da,d d Z-dZ.dZ/dZ0dZ1dZ2dZ3dZ4Gddde5Z6GdddZ7GdddZ8GdddZ9GdddZ:GdddZ;Gd d!d!ZGd&d'd'e5Z?dS)()print_functionN)lib bcc_symbolbcc_symbol_optionbcc_stacktrace_build_id _SYM_CB_TYPE)TablePerfEventArrayRingBufBPF_MAP_TYPE_QUEUEBPF_MAP_TYPE_STACK)Perf)get_online_cpusprintb_assert_is_bytes ArgString StrcmpRewrite) __version__)disassemble_prog decode_map)USDT USDTExceptionicCstS)N)_num_open_probesrr/usr/lib/python3.6/__init__.py_get_num_open_probes+srz/sys/kernel/debug/tracing c@s$eZdZddZddZddZdS) SymbolCachecCs tj|tjdtjt|_dS)N)rZbcc_symcache_newctcastPOINTERrcache)selfpidrrr__init__AszSymbolCache.__init__cCst}|r"tj|j|tj|}ntj|j|tj|}|dkrp|jrf|jrfd|jtj |jtj j fSd|dfS|r|j }tj tj|n|j}||jtj |jtj j fS)a Return a tuple of the symbol (function), its offset from the beginning of the function, and the module in which it lies. For example: ("start_thread", 0x202, "/usr/lib/.../libpthread-2.24.so") If the symbol cannot be found but we know which module it is in, return the module name and the offset from the beginning of the module. If we don't even know the module, return the absolute address as the offset. rN)rrZbcc_symcache_resolver&r#byrefZ bcc_symcache_resolve_no_demanglemoduleoffsetr$c_char_pvalueZ demangle_nameZbcc_symbol_free_demangle_namename)r'addrdemanglesymresZname_resrrrresolveEs     zSymbolCache.resolvecCs>t|}t|}tj}tj|j||tj|dkr8dS|jS)Nrr)rr# c_ulonglongrZbcc_symcache_resolve_namer&r*r.)r'r+r/r0rrr resolve_namebs zSymbolCache.resolve_nameN)__name__ __module__ __qualname__r)r4r7rrrrr"@sr"c@s$eZdZdZdZdZdZdZdZdS)PerfTyperrrrN) r8r9r:ZHARDWAREZSOFTWARE TRACEPOINTZHW_CACHERAWZ BREAKPOINTrrrrr;ks r;c@s4eZdZdZdZdZdZdZdZdZ dZ d Z d Z d S) PerfHWConfigrrrr<rr=r N) r8r9r:Z CPU_CYCLESZ INSTRUCTIONSZCACHE_REFERENCESZ CACHE_MISSESZBRANCH_INSTRUCTIONSZ BRANCH_MISSESZ BUS_CYCLESZSTALLED_CYCLES_FRONTENDZSTALLED_CYCLES_BACKENDZREF_CPU_CYCLESrrrrr@tsr@c@s8eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d S) PerfSWConfigrrrr<rr=rArBrrC N)r8r9r:Z CPU_CLOCKZ TASK_CLOCKZ PAGE_FAULTSZCONTEXT_SWITCHESZCPU_MIGRATIONSZPAGE_FAULTS_MINZPAGE_FAULTS_MAJZALIGNMENT_FAULTSZEMULATION_FAULTSZDUMMYZ BPF_OUTPUTrrrrrDsrDc@speZdZdZdZdZdZdZd Zd!Z d"Z d#Z d$Z d%Z d&Zd'Zd(Zd)Zd*Zd+Zd,Zd-Zd.Zd/Zd0Zd1Zd2Zd3ZdS)4PerfEventSampleFormatrrrr<rr=rArBrrCrE r Nrrrrr r!@iiiii i@iiiiiii i@ii)r8r9r:ZIPZTIDZTIMEZADDRZREADZ CALLCHAINZIDZCPUZPERIODZ STREAM_IDr?Z BRANCH_STACKZ REGS_USERZ STACK_USERZWEIGHTZDATA_SRCZ IDENTIFIERZ TRANSACTIONZ REGS_INTRZ PHYS_ADDRZAUXZCGROUPZDATA_PAGE_SIZEZCODE_PAGE_SIZEZ WEIGHT_STRUCTrrrrrFs2rFc@s`eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdS) BPFProgTyperrr<rr=rArBrrCrErGrHrIrJrKr rLrMN)r8r9r: SOCKET_FILTERKPROBE SCHED_CLS SCHED_ACTr>XDP PERF_EVENT CGROUP_SKB CGROUP_SOCKLWT_INLWT_OUTLWT_XMITSOCK_OPSSK_SKB CGROUP_DEVICESK_MSGRAW_TRACEPOINTCGROUP_SOCK_ADDRZCGROUP_SOCKOPTTRACINGLSMrrrrrWs*rWc@seZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!d Z"d!Z#d"Z$d#Z%d$Z&d%Z'd&Z(d'Z)d(S)) BPFAttachTyperrrr<rr=rArBrrCrErGrHrIrJrKr rLrMrNrOrPrQrRrSrXrYrZr!!"#$%&N)*r8r9r:ZCGROUP_INET_INGRESSZCGROUP_INET_EGRESSZCGROUP_INET_SOCK_CREATEZCGROUP_SOCK_OPSZSK_SKB_STREAM_PARSERZSK_SKB_STREAM_VERDICTrhZSK_MSG_VERDICTZCGROUP_INET4_BINDZCGROUP_INET6_BINDZCGROUP_INET4_CONNECTZCGROUP_INET6_CONNECTZCGROUP_INET4_POST_BINDZCGROUP_INET6_POST_BINDZCGROUP_UDP4_SENDMSGZCGROUP_UDP6_SENDMSGZ LIRC_MODE2ZFLOW_DISSECTORZ CGROUP_SYSCTLZCGROUP_UDP4_RECVMSGZCGROUP_UDP6_RECVMSGZCGROUP_GETSOCKOPTZCGROUP_SETSOCKOPTZ TRACE_RAW_TPZ TRACE_FENTRYZ TRACE_FEXITZ MODIFY_RETURNZLSM_MACZ TRACE_ITERZCGROUP_INET4_GETPEERNAMEZCGROUP_INET6_GETPEERNAMEZCGROUP_INET4_GETSOCKNAMEZCGROUP_INET6_GETSOCKNAMEZ XDP_DEVMAPZCGROUP_INET_SOCK_RELEASEZ XDP_CPUMAPZ SK_LOOKUPr_ZSK_SKB_VERDICTrrrrrnsNrnc@s eZdZdZdZdZdZdZdS) XDPActionrrrr<rN)r8r9r: XDP_ABORTEDXDP_DROPXDP_PASSXDP_TX XDP_REDIRECTrrrrrys ryc@s eZdZdZdZd Zd Zd ZdS) XDPFlagsrrrr<rNrrrrr )r8r9r:UPDATE_IF_NOEXISTSKB_MODEDRV_MODEHW_MODEREPLACErrrrrs rc@seZdZejZejZejZejZejZej Z ej Z ej Z ej Z ej Z ejZejZejZejZejZejZejZejZejZejZejZejZejZejZejZejZ ej!Z"ej#Z$ej%Z&ej'Z(e)j*dZ+iZ,e-j.Z/dgddgddgdgdd gd Z0d d d ddddgZ1dZ2Gddde3j4Z5e3j6dddZ7e7j8Z9e3j:e3j;e5ge9_e=ddZ?e@Z@GdddeAZBeCddZDeCd d!ZEd"d"d#d$ggdd#d%f d&d'ZFefd(d)ZGdd*d+ZHd,d-ZId.d/ZJdd0d1ZKe3jLe3jMe3jNe3jOe3jPe3jQe3j:e3jRe3jSe3jTe3jUe3jVe3jWe3jXe3jYe3jZd2e3j[d2d3Z\eCd4d5Z]dd6d7Z^d8d9Z_d:d;Z`dd?Zbd@dAZceCddBdCZdeCdDdEZeeCdFdGZfeCdHdIZgdJdKZheCdLdMZidNdOZjdPdQZkdRdSZldTdUZmdVdWZndXdYZodZd[Zpdd\d]Zqdd^d_Zrd`daZsdbdcZtddddeZuddfdgZveCddhdiZweCddjdkZxe=ddldmZyeCdndoZzeCdpdqZ{eCdrdsZ|ddtduZ}ddvdwZ~ddxdyZeCdzd{ZeCd|d}ZeCd~dZdddZdddZdddZdddZdddZdddZeCddZeCddZeCddZdddZddZdddZddZdddZdddZeCddZeCddZeCddZddZdddZd ddZddZd ddZd ddZddZdddZdddZdddZdddZeCddZeCdddZeCdddZeCddZddÄZddńZddDŽZdddɄZdd˄Zddd̈́ZdddτZdddфZddӄZddՄZeCddׄZddلZddۄZdd݄Zdd߄ZddZd#S(BPFs [^a-zA-Z0-9_]ZtimeZfsfileZbioZrequestZallocZsk_buffZ net_device)z linux/time.hz linux/fs.hzlinux/blkdev.hz linux/slab.hzlinux/netdevice.hssys_s __x64_sys_s__x32_compat_sys_s__ia32_compat_sys_s __arm64_sys_s __s390x_sys_s __s390_sys_rc@s eZdZdejfdejfgZdS)z BPF.timespectv_sectv_nsecN)r8r9r:r#c_long_fields_rrrrtimespec@srz librt.so.1T)Z use_errnocCsH|j}|j|jtj|dkr8tj}t|tj||j d|j S)zmonotonic_time() Returns the system monotonic time from clock_gettime, using the CLOCK_MONOTONIC constant. The time returned is in nanoseconds. rgeA) r_clock_gettimeCLOCK_MONOTONICr#r* get_errnoOSErrorosstrerrorrr)clsterrnorrrmonotonic_timeGs zBPF.monotonic_timecCsXd}xN|jjD]@\}}x6|D].}x(|D] }||kr(||kr(|d|7}q(WqWqW|S)a1 Generates #include statements automatically based on a set of recognized types such as sk_buff and bio. The input is all the words that appear in the BPF program, and the output is a (possibly empty) string of #include statements, such as "#include ". z#include <%s> )_auto_includesitems)rZ program_wordsZheadersheaderkeywordskeywordZwordrrrgenerate_auto_includesSs  zBPF.generate_auto_includesc@seZdZddZdS)z BPF.FunctioncCs||_||_||_dS)N)bpfr/fd)r'rr/rrrrr)gszBPF.Function.__init__N)r8r9r:r)rrrrFunctionfsrcCsb|r^tjj|s^ttjd}djtjjtjj|j |g}tjj|rR|}n t d||S)z1 If filename is invalid, search in ./ of argv[0] r/zCould not find file %s) rpathisfilersysargvjoinabspathdirname __bytes__ Exception)filenameZargv0rrrr _find_filels "  zBPF._find_filecCsrdd}tjj|\}}|r*||rn|SnDxBtjdjtjD],}|jd}tjj|j|}||r>|Sq>WdS)a find_exe(bin_path) Traverses the PATH environment variable, looking for the first directory that contains an executable file named bin_path, and returns the full path to that file, or None if no such file can be found. This is meant to replace invocations of the "which" shell utility, which doesn't have portable semantics for skipping aliases. cSstjj|otj|tjS)N)rrraccessX_OK)fpathrrris_exes zBPF.find_exe..is_exePATH"N)rrsplitenvironpathsepstriprencode)Zbin_pathrrZfnamerZexe_filerrrfind_exeys  z BPF.find_exeNrFc Cst|}t|}t|}|o| s&ti|_i|_i|_i|_i|_i|_i|_i|_ i|_ d|_ d|_ t j|j||_i|_i|_d|_tjt|} x$t|D]\} } tt| | | <qW|rtj|}tj|}|rt|dd} | j}WdQRXtjt|}x(t|D]\} }tj|j|| <qWt j!|t|}|dkrZt"d ||}t j#||j| t| |||_|jst"d|pd x|D]}|j$|| qW|j%dS) aZCreate a new BPF module with the given source code. Note: All fields are marked as optional, but either `src_file` or `text` must be supplied, and not both. Args: src_file (Optional[str]): Path to a source file for the module hdr_file (Optional[str]): Path to a helper header file for the `src_file` text (Optional[str]): Contents of a source file for the module debug (Optional[int]): Flags used for debug prints, can be |'d together See "Debug flags" for explanation Nrb)modez%can't generate USDT probe arguments; z%possible cause is missing pid when a z&probe in a shared object has multiple Z locationszFailed to compile BPF module %szzJcan't generate USDT probe arguments; possible cause is missing pid when a zpcan't generate USDT probe arguments; possible cause is missing pid when a probe in a shared object has multiple zycan't generate USDT probe arguments; possible cause is missing pid when a probe in a shared object has multiple locations)&rAssertionError kprobe_fds uprobe_fdstracepoint_fdsraw_tracepoint_fdskfunc_entry_fdskfunc_exit_fdslsm_fds perf_buffersopen_perf_events_ringbuf_manager tracefileatexitregistercleanupdebugfuncstablesr+r#r-len enumeratebytesrrropenreadc_void_pZ get_contextrZbcc_usdt_genargsrZbpf_module_create_c_from_stringZattach_uprobes_trace_autoload)r'Zsrc_fileZhdr_filetextrZcflagsZ usdt_contextsZ allow_rlimitdeviceZattach_usdt_ignore_pidZ cflags_arrayisrZ ctx_arrayusdtZ usdt_textZ usdt_contextrrrr)s^      z BPF.__init__cCsDg}x:tdtj|jD]$}tj|j|}|j|j||qW|S)zload_funcs(prog_type=KPROBE) Load all functions in this BPF module with the given type. Returns a list of the function handles.r)rangerbpf_num_functionsr+bpf_function_nameappend load_func)r' prog_typefnsr func_namerrr load_funcss zBPF.load_funcsc Cst|}||jkr|j|Stj|j|s6td|d}|jt@rJd}n|jt@rXd}tj |j||tj|j|tj |j|tj |jtj |j|dd|| }|dkrt j|jtjtjkrtdtjtj}td||ftj|||}||j|<|S)NzUnknown program %srrrz!Need super-user privileges to runz!Failed to load BPF program %s: %s)rrrbpf_function_startr+rrDEBUG_BPF_REGISTER_STATE DEBUG_BPFZ bcc_func_loadbpf_function_sizeZbpf_module_licenseZbpf_module_kern_versionrr donothingr#rrEPERMrrrr) r'rrr attach_typeZ log_levelrerrstrfnrrrrs4             z BPF.load_funccCsJt|}tj|j|s"td|tj|j|}tj|j|}tj||S)zR Return the eBPF bytecodes for the specified function as a string zUnknown program %s)rrrr+rrr#Z string_at)r'rstartsizerrr dump_funcs  z BPF.dump_funccCs|j|}t||S)N)rr)r'rZbpfstrrrrdisassemble_funcs zBPF.disassemble_funccCs(||}tj|j|j}t||||dS)N)sizeinfo)rbpf_table_type_idr+map_idr)r'Z table_namerZ table_objZ table_typerrr decode_table#szBPF.decode_tabler)Z_BoolcharZwchar_tz unsigned charZshortzunsigned shortintz unsigned intZlongz unsigned longz long longzunsigned long longfloatZdoublez long doubleZ__int128zunsigned __int128cCst|trtj|Sg}g}xN|dD]@}t|dkrX|j|dtj|dfq(t|dkrZt|dtr|j|dtj|d|ddfnt|dtr|j|dtj|d|dfnt|dtrH|ddks |ddks |ddkrH|d}|dkr2d t|}|j||j|tj|fnt d t |q(t d t |q(Wt j }d }t|dkr|ddkrt j }n.|ddkrt j }n|ddkrt j }d }|rtt |d|ft|d|d }ntt |d|ft||d}|S)Nrrrr<unionstructZ struct_packedrz__anon%dzFailed to decode type %sFT) _anonymous_Z_pack_r)rr) isinstance basestringr str2ctyperr_decode_table_typelistrrstrr# StructureZUniontypedict)ZdescZanonfieldsrr/baseZ is_packedrrrrr;sL   *$     zBPF._decode_table_typec Cst|}tj|j|}tj|j|}tj|j|ttgk}|dkrFt| r| rtj |j|j d}|svt d|t j tj|}|stj|j|j d} | st d|t j tj| }t|||||||dS)Nrzutf-8z$Failed to load BPF Table %s key descz%Failed to load BPF Table %s leaf desc)reducer)rrZ bpf_table_idr+Z bpf_table_fdrr r KeyErrorZbpf_table_key_descdecoderrrjsonloadsZbpf_table_leaf_descr ) r'r/ZkeytypeZleaftyperrmap_fdZ is_queuestackZkey_descZ leaf_descrrr get_tablegs"   z BPF.get_tablecCs$||jkr|j||j|<|j|S)N)rr )r'keyrrr __getitem__zs zBPF.__getitem__cCs||j|<dS)N)r)r'r Zleafrrr __setitem__szBPF.__setitem__cCs t|jS)N)rr)r'rrr__len__sz BPF.__len__cCs |j|=dS)N)r)r'r rrr __delitem__szBPF.__delitem__cCs |jjS)N)r__iter__)r'rrrrsz BPF.__iter__cCsJt|tjstdtj|j|||}|dkrFtdj|tj | dS)Nz"arg 1 must be of type BPF.Functionrz7Failed to attach BPF function with attach_type {0}: {1}) rrrrrZbpf_prog_attachrformatrr)r attachable_fdrflagsr3rrr attach_funcs  zBPF.attach_funccCsHt|tjstdtj|j||}|dkrDtdj|tj | dS)Nz"arg 1 must be of type BPF.Functionrz7Failed to detach BPF function with attach_type {0}: {1}) rrrrrZbpf_prog_detach2rrrr)rrrr3rrr detach_funcs  zBPF.detach_funccCst|}t|tjstdtj|}|dkrLtjt j }td||ftj ||j }|dkrtjt j }td||f||_ dS)Nz"arg 1 must be of type BPF.Functionrz Failed to open raw device %s: %sz%Failed to attach BPF to device %s: %s)rrrrrrZbpf_open_raw_sockrrr#rZbpf_attach_socketrsock)rdevrrr3rrrattach_raw_sockets   zBPF.attach_raw_socketc Csdt}y,t|d}tdd|D}WdQRXWn:tk rn}z|jtjkrV|tg}WYdd}~XnXg}d}d}tdd}x |D]} | jjdd\} } |dkr| d krd}qn|dkr| d krd }q|dkr | d krd}qn| d kr"d }qn|dkr"| d krd }q| jdr2qn:| jds| jdrLqn | jdr\qnt j d| rlq| j dkrt j || r| |kr|j | qWWdQRXt|S)Nz%s/../kprobes/blacklistrcSsg|]}|jjdqS)r)rstripr).0linerrr sz,BPF.get_kprobe_functions..rz/proc/kallsymsrr<s __init_begins __init_endrs__irqentry_text_starts__irqentry_text_ends _kbl_addr_s__perfsperf_s__SCT__s^.*\.cold(\.\d+)?$tw)rr)TRACEFSrsetIOErrorrrrr startswithrematchlower fullmatchr) event_reZblacklist_fileZ blacklist_fZ blacklisterZin_init_sectionZin_irq_sectionZ avail_filerrrrrrget_kprobe_functionssZ        zBPF.get_kprobe_functionscCst|tjkrtddS)Nz/Number of open probes would exceed global quota)rrget_probe_limitr)r'Znum_new_probesrrr_check_probe_quotaszBPF._check_probe_quotacCs(tjjd}|r |jr t|StSdS)NZBCC_PROBE_LIMIT)rrgetisdigitr_default_probe_limit)Zenv_probe_limitrrrr*s  zBPF.get_probe_limitcCs.||jkri|j|<||j||<td7adS)Nr)rr)r'ev_namefn_namerrrr_add_kprobe_fds  zBPF._add_kprobe_fdcCs|j||=td8adS)Nr)rr)r'r/r0rrr_del_kprobe_fds zBPF._del_kprobe_fdcCs||j|<td7adS)Nr)rr)r'r/rrrr_add_uprobe_fd s zBPF._add_uprobe_fdcCs|j|=td8adS)Nr)rr)r'r/rrr_del_uprobe_fdszBPF._del_uprobe_fdcCs0x$|jD]}|jd|dkr|SqW|jdS)Ns%sbpfrrr5)_syscall_prefixesksymname)r'prefixrrrget_syscall_prefixs zBPF.get_syscall_prefixcCst|}|j|S)N)rr8)r'r/rrrget_syscall_fnname szBPF.get_syscall_fnnamecCs<t|}x.|jD]$}|j|r|j|t|dSqW|S)N)rr5r"r9r)r'r/r7rrrfix_syscall_fnname's   zBPF.fix_syscall_fnnamec Cst|}t|}t|}|rtj|}|jt|d}g}x>|D]6}y|j||dWqB|d7}|j|YqBXqBW|t|krtd|dj|fdS|jd|j |tj } d|j ddj d d} t j | jd| ||d} | dkrtd||f|j| || |S) Nr)eventr0rzwFailed to attach BPF program %s to kprobe %s, it's not traceable (either non-existing, inlined, or marked as "notrace")/sp_+_.)rrr)r+r attach_kproberrrrr\replacerbpf_attach_kproberr1) r'r;Z event_offr0r'matchesfailedprobesrrr/rrrrr@.s6      zBPF.attach_kprobec Cst|}t|}t|}|rtj|}d}g}x@|D]8}y|j|||dWq4|d7}|j|Yq4Xq4W|t|krtd|dj|fdS|jd|j |tj } d|j ddj d d} t j | jd| |d|} | dkrtd||f|j| || |S) Nr)r;r0 maxactiverzzFailed to attach BPF program %s to kretprobe %s, it's not traceable (either non-existing, inlined, or marked as "notrace")r<sr_r=r>r?)rrr)attach_kretproberrrrr+rr\rArrBrr1) r'r;r0r'rFrCrDrErrr/rrrrrGPs6      zBPF.attach_kretprobecCs8t|}t|j|j}x|D]}|j||q WdS)N)rrrkeysdetach_kprobe_event_by_fn)r'r/Zfn_namesr0rrrdetach_kprobe_eventrs zBPF.detach_kprobe_eventcCst|}t|}||jkr&td|tj|j||}|dkrJtd|j||t|j|dkrtj|}|dkrtddS)NzKprobe %s is not attachedrzFailed to close kprobe FDz Failed to detach BPF from kprobe)rrrrbpf_close_perf_event_fdr2rZbpf_detach_kprobe)r'r/r0r3rrrrIxs    zBPF.detach_kprobe_event_by_fncCsHt|}d|jddjdd}|r:t|}|j||n |j|dS)Nsp_r=r>r?)rrArIrJ)r'r;r0r/rrr detach_kprobes zBPF.detach_kprobecCsHt|}d|jddjdd}|r:t|}|j||n |j|dS)Nsr_r=r>r?)rrArIrJ)r'r;r0r/rrrdetach_kretprobes zBPF.detach_kretprobecCsnt|}t|tjstdtj||j|}|dkrjtj }|t j krPtdnt j |}td||fdS)zt This function attaches a BPF function to a device on the device driver level (XDP) z"arg 1 must be of type BPF.Functionrz-Internal error while attaching BPF to device,z try increasing the debug level!z%Failed to attach BPF to device %s: %sNzMInternal error while attaching BPF to device, try increasing the debug level!)rrrrrrbpf_attach_xdprr#rrZEBADMSGrr)rrrr3Zerr_norrrr attach_xdps   zBPF.attach_xdpcCs@t|}tj|d|}|dkrqxRtj|D]D}tjj||}tjj|rJd||f}tj|j|rJ|j |qJWqW|S)Neventsz%s:%s) rrrrlistdirisdirr#r$rr)tp_reresultsZ events_dircategoryZcat_dirr;evt_dirtprrrget_tracepointss   zBPF.get_tracepointscCstjjtd||}tjj|S)NrU)rrrrrW)rZr;r[rrrtracepoint_existsszBPF.tracepoint_existscCst|}t|}t|}|rBx tj|D]}|j||dq(WdS|j|tj}|jd\}}tj|j ||}|dkrt d||f||j |<|S)aattach_tracepoint(tp="", tp_re="", fn_name="") Run the bpf function denoted by fn_name every time the kernel tracepoint specified by 'tp' is hit. The optional parameters pid, cpu, and group_fd can be used to filter the probe. The tracepoint specification is simply the tracepoint category and the tracepoint name, separated by a colon. For example: sched:sched_switch, syscalls:sys_enter_bind, etc. Instead of a tracepoint name, a regular expression can be provided in tp_re. The program will then attach to tracepoints that match the provided regular expression. To obtain a list of kernel tracepoints, use the tplist tool or cat the file /sys/kernel/debug/tracing/available_events. Examples: BPF(text).attach_tracepoint(tp="sched:sched_switch", fn_name="on_switch") BPF(text).attach_tracepoint(tp_re="sched:.*", fn_name="on_switch") )r\r0N:rz0Failed to attach BPF program %s to tracepoint %s) rrr]attach_tracepointrr>rrZbpf_attach_tracepointrrr)r'r\rXr0r tp_categorytp_namerrrrr`s  zBPF.attach_tracepointcCs`t|}||jkrtd|t|}|j|tj}tj|j|}|dkrRtd||j|<|S)aattach_raw_tracepoint(self, tp=b"", fn_name=b"") Run the bpf function denoted by fn_name every time the kernel tracepoint specified by 'tp' is hit. The bpf function should be loaded as a RAW_TRACEPOINT type. The fn_name is the kernel tracepoint name, e.g., sched_switch, sys_enter_bind, etc. Examples: BPF(text).attach_raw_tracepoint(tp="sched_switch", fn_name="on_switch") z#Raw tracepoint %s has been attachedrz&Failed to attach BPF to raw tracepoint) rrrrrrjrZbpf_attach_raw_tracepointr)r'r\r0rrrrrattach_raw_tracepoints    zBPF.attach_raw_tracepointcCs:t|}||jkrtd|tj|j||j|=dS)zdetach_raw_tracepoint(tp="") Stop running the bpf function that is attached to the kernel tracepoint specified by 'tp'. Example: bpf.detach_raw_tracepoint("sched_switch") z!Raw tracepoint %s is not attachedN)rrrrclose)r'r\rrrdetach_raw_tracepoint)s   zBPF.detach_raw_tracepointcCs|j|s||}|S)N)r")r7r/rrr add_prefix8s zBPF.add_prefixcCs2tjdkrdStjsdStjddkr.dSdS)NZx86_64FZbpf_trampoline_link_progrTr5)platformmachinerbpf_has_kernel_btfrr6rrrr support_kfunc>s zBPF.support_kfunccCs"tjs dStjddkrdSdS)NFs bpf_lsm_bpfrTr5)rrirr6rrrr support_lsmJs zBPF.support_lsmcCsFt|}tjd|}||jkr*td|tj|j||j|=dS)Nskfunc__z$Kernel entry func %s is not attached)rrrfrrrrd)r'r0rrr detach_kfuncSs    zBPF.detach_kfunccCsFt|}tjd|}||jkr*td|tj|j||j|=dS)Ns kretfunc__z#Kernel exit func %s is not attached)rrrfrrrrd)r'r0rrrdetach_kretfunc\s    zBPF.detach_kretfunccCsbt|}tjd|}||jkr*td||j|tj}tj|j }|dkrTtd||j|<|S)Nskfunc__z&Kernel entry func %s has been attachedrz)Failed to attach BPF to entry kernel func) rrrfrrrrlrbpf_attach_kfuncr)r'r0rrrrr attach_kfunces     zBPF.attach_kfunccCsbt|}tjd|}||jkr*td||j|tj}tj|j }|dkrTtd||j|<|S)Ns kretfunc__z%Kernel exit func %s has been attachedrz(Failed to attach BPF to exit kernel func) rrrfrrrrlrrnr)r'r0rrrrrattach_kretfuncss     zBPF.attach_kretfunccCsFt|}tjd|}||jkr*td|tj|j||j|=dS)Nslsm__zLSM %s is not attached)rrrfrrrrd)r'r0rrr detach_lsms    zBPF.detach_lsmcCsbt|}tjd|}||jkr*td||j|tj}tj|j }|dkrTtd||j|<|S)Nslsm__zLSM %s has been attachedrzFailed to attach LSM) rrrfrrrrmrZbpf_attach_lsmr)r'r0rrrrr attach_lsms     zBPF.attach_lsmcCs$tjddkstjddkr dSdS)NZbpf_find_raw_tracepointrZbpf_get_raw_tracepointTFr5r5)rr6rrrrsupport_raw_tracepointszBPF.support_raw_tracepointc CsZd}t|D}x<|D]4}|jjdd\}}}|jdd}|dkrdSqWdSQRXdS) Nz/proc/kallsyms r rZbpf_trace_modulesTF)rrr)ZkallsymsZsymsr_r/rrr support_raw_tracepoint_in_modules  z$BPF.support_raw_tracepoint_in_modulecCst|}t|}tj||S)N)rrkernel_struct_has_field)Z struct_nameZ field_namerrrrxszBPF.kernel_struct_has_fieldcCstt|}||jkrtd|tj|j|}|dkr>td|jd\}}tj||}|dkrhtd|j|=dS)zdetach_tracepoint(tp="") Stop running a bpf function that is attached to the kernel tracepoint specified by 'tp'. Example: bpf.detach_tracepoint("sched:sched_switch") zTracepoint %s is not attachedrz$Failed to detach BPF from tracepointr_N)rrrrrKrZbpf_detach_tracepoint)r'r\r3rarbrrrdetach_tracepoints    zBPF.detach_tracepointc Cs,tj||||||||} | dkr(td| S)Nrz"Failed to attach BPF to perf event)rZbpf_attach_perf_eventr) r'progfdev_type ev_config sample_period sample_freqr(cpugroup_fdr3rrr_attach_perf_events  zBPF._attach_perf_eventc Cst|}|j|tj} i} |dkrB|j| j|||||||| |<n.x,tD]"} |j| j|||||| || | <qJW| |j||f<dS)Nr)rrrr`rrrr) r'r{r|r0r}r~r(rrrr3rrrrattach_perf_events   zBPF.attach_perf_eventcCs.tj|tj||||d}|dkr*td|S)Nrz&Failed to attach BPF to perf raw event)rZbpf_attach_perf_event_rawr#r*r)r'rzattrr(rrr3rrr_attach_perf_event_raws  zBPF._attach_perf_event_rawc Cszt|}|j|tj}i}|dkr<|j|j||||||<n(x&tD]}|j|j||||||<qDW||j|j|j f<dS)Nr) rrrr`rrrrrconfig) r'rr0r(rrrr3rrrrattach_perf_event_raws   zBPF.attach_perf_event_rawc Cs|y|j||f}Wn$tk r6tdj||YnXd}x|jD]}tj|pV|}qFW|dkrltd|j||f=dS)Nz)Perf event type {} config {} not attachedrz$Failed to detach BPF from perf event)rrrrvaluesrrK)r'r{r|Zfdsr3rrrrdetach_perf_eventszBPF.detach_perf_eventcCstddtj||DS)NcSsg|] \}}|qSrr)rr/rvrrrrsz*BPF.get_user_functions..)r r get_user_functions_and_addresses)r/sym_rerrrget_user_functionsszBPF.get_user_functionscCstddtj||DS)a We are returning addresses here instead of symbol names because it turns out that the same name may appear multiple times with different addresses, and the same address may appear multiple times with the same name. We can't attach a uprobe to the same address more than once, so it makes sense to return the unique set of addresses that are mapped to a symbol that matches the provided regular expression. cSsg|] \}}|qSrr)rrvZaddressrrrrsz*BPF.get_user_addresses..)r rr)r/rrrrget_user_addressess zBPF.get_user_addressescsNt|}tgfdd}tj|t|}|dkrJtd||fS)Ncs"|}tj|rj||fdS)Nr)r#r$r)Zsym_namer0Zdname) addressesrrrsym_cbs z4BPF.get_user_functions_and_addresses..sym_cbrz"Error %d enumerating symbols in %s)rrZbcc_foreach_function_symbolrr)r/rrr3r)rrrrsz$BPF.get_user_functions_and_addressescCs>|dkr d||jjd||fSd||jjd|||fSdS)Nrs %s_%s_0x%xr>s %s_%s_0x%x_%dr5) _probe_replsub)r'r7rr0r(rrr_get_uprobe_evname!szBPF._get_uprobe_evnamecCs|dks t|dk r$|dks$tdt|}t|}t|}t|}|rtj||}|jt|x|D]} |j|| ||dqhWdStj|||||\} }|jd|j|tj } |j d| ||} t j | j d| | ||} | dkrtd|j| | |S)aattach_uprobe(name="", sym="", sym_re="", addr=None, fn_name="" pid=-1, sym_off=0) Run the bpf function denoted by fn_name every time the symbol sym in the library or binary 'name' is encountered. Optional parameters pid, cpu, and group_fd can be used to filter the probe. If sym_off is given, attach uprobe to offset within the symbol. The real address addr may be supplied in place of sym, in which case sym must be set to its default value. If the file is a non-PIE executable, addr must be a virtual address, otherwise it must be an offset relative to the file load address. Instead of a symbol name, a regular expression can be provided in sym_re. The uprobe will then attach to symbols that match the provided regular expression. Libraries can be given in the name argument without the lib prefix, or with the full path (/usr/lib/...). Binaries can be given only with the full path (/bin/sh). If a PID is given, the uprobe will attach to the version of the library used by the process. Example: BPF(text).attach_uprobe("c", "malloc") BPF(text).attach_uprobe("/usr/bin/python", "main") rNz!offset with addr is not supported)r/r0r0r(rpzFailed to attach BPF to uprobe)rrrrr+r attach_uproberSrr\rrbpf_attach_uproberrr3)r'r/r2rr0r0r(rRrsym_addrrrr/rrrrr)s.     zBPF.attach_uprobec Cst|}t|}t|}t|}|rPx&tj||D]}|j||||dq2WdStj||||\}}|jd|j|tj} |jd|||} t j | j d| |||} | dkrt d|j | | |S)a6attach_uretprobe(name="", sym="", sym_re="", addr=None, fn_name="" pid=-1) Run the bpf function denoted by fn_name every time the symbol sym in the library or binary 'name' finishes execution. See attach_uprobe for meaning of additional parameters. )r/r0r0r(Nrrrz!Failed to attach BPF to uretprobe)rrrattach_uretproberSr+rr\rrrrrr3) r'r/r2rr0r0r(rrrr/rrrrrbs$   zBPF.attach_uretprobecCs^||jkrtd|tj|j|}|dkr6tdtj|}|dkrPtd|j|dS)NzUprobe %s is not attachedrz Failed to detach BPF from uprobe)rrrrKZbpf_detach_uprober4)r'r/r3rrrdetach_uprobe_events   zBPF.detach_uprobe_eventcCsDt|}t|}tj|||||\}}|jd|||}|j|dS)zdetach_uprobe(name="", sym="", addr=None, pid=-1) Stop running a bpf function that is attached to symbol 'sym' in library or binary 'name'. rN)rrrSrr)r'r/r2r0r(rRrr/rrr detach_uprobes zBPF.detach_uprobecCsBt|}t|}tj||||\}}|jd|||}|j|dS)zdetach_uretprobe(name="", sym="", addr=None, pid=-1) Stop running a bpf function that is attached to symbol 'sym' in library or binary 'name'. rN)rrrSrr)r'r/r2r0r(rr/rrrdetach_uretprobes zBPF.detach_uretprobecCsnxftdtj|jD]N}tj|j|}|jdrb|j|tj}|j |j |dd|j dq|jdr|j|tj}|j |j |dd|j dq|jdr|j|tj }|j tddjdd }|j||j d q|jd r|j|tj}|j td d}|j||j d q|jd r6|j|d q|jdrP|j|d q|jdr|j|d qWdS)Nrskprobe__r)r;r0s kretprobe__rGs tracepoint__s__r_)r\r0sraw_tracepoint__skfunc__)r0s kretfunc__slsm__)rrrr+rr"rrr\r@r:r/rGr>rrAr`rjrcrorprr)r'rrrr\rrrrs4         zBPF._trace_autoloadcCsN|jsHtdtd|_|rH|jj}tj|tj}tj|tj|tjB|jS)zWtrace_open(nonblocking=False) Open the trace_pipe if not already open z %s/trace_piper) rrrfilenofcntlZF_GETFLZF_SETFLr O_NONBLOCK)r' nonblockingrZflrrr trace_opens zBPF.trace_openc Csx|j|}| r|rd S|jdr(q|ddj}|dd}|jd}y|d|j\}}}}Wn$tk r} zwWYdd} ~ XnX|dd}||dd}|jd} || dd} y|t|t||t|| fStk r} zdSd} ~ XqXqWdS)ztrace_fields(nonblocking=False) Read from the kernel debug trace pipe and return a tuple of the fields (task, pid, cpu, flags, timestamp, msg) or None if no line was read (nonblocking=True) NrAsCPU:r rLr_rrUnknownr)N)NNNNNNr5)rrrrrr)trace_readliner"lstripfindrrrr) r'rrZtaskZts_endr(rrZtsr(Zsym_endmsgrrr trace_fieldss*       zBPF.trace_fieldsc Cs:|j|}d}y|jdj}Wntk r4YnX|S)ztrace_readline(nonblocking=False) Read from the kernel debug trace pipe and return one line If nonblocking is False, this will block until ctrl-C is pressed. Ni)rreadlinerr!)r'rZtracerrrrrs zBPF.trace_readlinecCsJxD|r$|jdd}|sq|j|}n |jdd}t|tjjqWdS)atrace_print(self, fmt=None) Read from the kernel debug trace pipe and print on stdout. If fmt is specified, apply as a format string to the output. See trace_fields for the members of the tuple example: trace_print(fmt="pid {1}, msg = {5}") F)rN)rrrprintrstdoutflush)r'Zfmtrrrrr trace_prints    zBPF.trace_printcCs6|dkr|dkrd}|tjkr,t|tj|<tj|S)z_sym_cache(pid) Returns a symbol cache for the specified PID. The kernel symbol cache is accessed by providing any PID less than zero. rrr5r5)r _sym_cachesr")r(rrr _sym_caches  zBPF._sym_cachec Cs6tt|}|jdd krt}t}|j|_|j|_|j|j_t j t j t j|t j|}|dkr|jr|jrd|jt j|jt jj} } } qd|d} } } q|j|jt j|jt jj} } } nt j|j||\} } } |r| dk rd| nd} | pd} | | } |r*| dk r*dtjj| nd} | | S) aysym(addr, pid, show_module=False, show_offset=False) Translate a memory address into a function name for a pid, which is returned. When show_module is True, the module name is also included. When show_offset is True, the instruction offset as a hexadecimal number is also included in the string. A pid of less than zero will access the kernel symbol cache. Example output when both show_module and show_offset are True: "start_thread+0x202 [libpthread-2.24.so]" Example output when both show_module and show_offset are False: "start_thread" Zbpf_stack_build_idrrNs+0x%xrs [unknown]s [%s]r5)rrrrrZstatusZbuild_idr,urZbcc_buildsymcache_resolver _bsymcacher#r*r+r$r-r.r/rr4rrbasename) r0r( show_module show_offsetr1Z typeofaddrr2br3r/r,r+rrrr2$s.     $zBPF.symcCstj|d||dS)aksym(addr) Translate a kernel memory address into a kernel function name, which is returned. When show_module is True, the module name ("kernel") is also included. When show_offset is true, the instruction offset as a hexadecimal number is also included in the string. Example output when both show_module and show_offset are True: "default_idle+0x0 [kernel]" rFr5)rr2)r0rrrrrksymUs zBPF.ksymcCstjdjd|S)zksymname(name) Translate a kernel name into an address. This is the reverse of ksym. Returns -1 when the function name is unknown.rNr5)rrr7)r/rrrr6csz BPF.ksymnamecCs t|jS)znum_open_kprobes() Get the number of open K[ret]probes. Can be useful for scenarios where event_re is used while attaching and detaching probes. )rr)r'rrrnum_open_kprobeskszBPF.num_open_kprobescCs t|jS)zInum_open_uprobes() Get the number of open U[ret]probes. )rr)r'rrrnum_open_uprobessszBPF.num_open_uprobescCs t|jS)zLnum_open_tracepoints() Get the number of open tracepoints. )rr)r'rrrnum_open_tracepointszszBPF.num_open_tracepointscCsLtjt|j}x"t|jjD]\}}|||<q"Wtjt|||dS)zperf_buffer_poll(self) Poll from all open perf ring buffers, calling the callback that was provided when calling open_perf_buffer for each entry. N)r#rrrrrrZperf_reader_poll)r'timeoutreadersrvrrrperf_buffer_polls zBPF.perf_buffer_pollcCsJtjt|j}x"t|jjD]\}}|||<q"Wtjt||dS)zperf_buffer_consume(self) Consume all open perf buffers, regardless of whether or not they currently contain events data. Necessary to catch 'remainder' events when wakeup_events > 1 is set in open_perf_buffer N)r#rrrrrrZperf_reader_consume)r'rrrrrrperf_buffer_consumes zBPF.perf_buffer_consumecCs|j|dS)zMkprobe_poll(self) Deprecated. Use perf_buffer_poll instead. N)r)r'rrrr kprobe_pollszBPF.kprobe_pollcCsL|js&tj||||_|jsHtdn"tj|j|||}|dkrHtddS)NzCould not open ring bufferr)rrZbpf_new_ringbufrZbpf_add_ringbuf)r'r rZctxretrrr_open_ring_buffers zBPF._open_ring_buffercCs |jstdtj|j|dS)zring_buffer_poll(self) Poll from all open ringbuf buffers, calling the callback that was provided when calling open_ring_buffer for each entry. zNo ring buffers to pollN)rrrZbpf_poll_ringbuf)r'rrrrring_buffer_pollszBPF.ring_buffer_pollcCs|jstdtj|jdS)a/ring_buffer_consume(self) Consume all open ringbuf buffers, regardless of whether or not they currently contain events data. This is best for use cases where low latency is desired, but it can impact performance. If you are unsure, use ring_buffer_poll instead. zNo ring buffers to pollN)rrrZbpf_consume_ringbuf)r'rrrring_buffer_consumeszBPF.ring_buffer_consumecCstjS)N)rZbcc_free_memory)r'rrrfree_bcc_memoryszBPF.free_bcc_memorycCsNytjtj|jWn2tk rH}ztdt|WYdd}~XnXdS)zJadd_module(modname) Add a library or exe to buildsym cache z&Error adding module to build sym cacheN)rZbcc_buildsymcache_add_modulerrrrrr)modnamer(rrr add_moduleszBPF.add_modulecCsdS)zthe do nothing exit handlerNr)r'rrrrsz BPF.donothingcCsLx.t|jjD]\}}tj|j|j|=qW|jrHtj|jd|_dS)zvclose(self) Closes all associated files descriptors. Attached BPF programs are not detached. N) rrrrrdrr+rZbpf_module_destroy)r'r/rrrrrds    z BPF.closecCsx$t|jjD]\}}|j|qWx$t|jjD]\}}|j|q6Wx$t|jjD]\}}|j|q\Wx$t|jjD]\}}|j |qWx$t|j jD]\}}|j |qWx$t|j jD]\}}|j |qWx$t|jjD]\}}|j|qWt|jj}x(|D] }t|j|tr|j|=qWx(t|jjD]\}}|j||qRW|jr|jjd|_|j|jrtj|jd|_dS)N)rrrrJrrrryrrerrlrrmrrqrrHrr rrrrdrrZbpf_free_ringbuf)r'krZ table_keysr r{r|rrrrs6   z BPF.cleanupcCs|S)Nr)r'rrr __enter__sz BPF.__enter__cCs |jdS)N)r)r'exc_typeZexc_valZexc_tbrrr__exit__sz BPF.__exit__r5)Nr5)F)NNN)r)rrrr)rrrr)N)N)r)r)r)rrr)rr)r)r)r)r)r)r)r)rr5r5r5r5r5)r5r5rrrr5r5r5r5r5r5r5)r5rr5r5r5r5r5)r5r5r5)rrrNrr5rr5)rrrNrr5r5)rrNr5rr5)rrNr5)F)F)F)N)FFT)FFr5)r5r5)r5)Nr5)r5)r8r9r:rWr[r\r]r^r>r_r`rarbrcrdrerfrgrhrirjrkrlrmryrzr{r|r}r~rrZXDP_FLAGS_UPDATE_IF_NOEXISTrZXDP_FLAGS_SKB_MODErZXDP_FLAGS_DRV_MODErZXDP_FLAGS_HW_MODErZXDP_FLAGS_REPLACEr#compilerrrZbcc_buildsymcache_newrrr5rr#rrZCDLLZ_librtZ clock_gettimerZc_intr%Zargtypes classmethodrrr objectr staticmethodrrr)rrrrrZc_boolZc_charZc_wcharZc_ubyteZc_shortZc_ushortZc_uintrZc_ulongZ c_longlongr6Zc_floatZc_doubleZ c_longdoubleZc_int64Zc_uint64rrr r r rrrrrrr)r+r*r1r2r3r4r8r9r:r@rGrJrIrLrMrOrPrSrTr]r^r`rcrerfrjrkrlrmrorprqrrrsrwrxryrrrrrrrrrrrrrrrrrrrrr2rr6rrrrrrrrrrrrrdrrrrrrrrsb     N    ,   B   " "       &              8   #   0       #r)@Z __future__rrZctypesr#rrrr#rrrgZlibbccrrrrrtabler r r r r ZperfrZutilsrrrrrversionrZ disassemblerrrrrrr NameErrorrr.rrrZ DEBUG_LLVM_IRrZDEBUG_PREPROCESSORZ DEBUG_SOURCErZ DEBUG_BTFrr"r;r@rDrFrWrnryrrrrrrsP    +  * __pycache__/tcp.cpython-36.opt-1.pyc000064400000001724152344707330013143 0ustar003 :)g2@siZded<ded<ded<ded<ded <d ed <d ed <ded<ded<ded<ded<ded<dZdZdZdZdZdZdZdZddZ dS)Z ESTABLISHEDZSYN_SENTZSYN_RECVZ FIN_WAIT1Z FIN_WAIT2Z TIME_WAITZCLOSEZ CLOSE_WAITZLAST_ACK ZLISTEN ZCLOSING Z NEW_SYN_RECV  @cCsg}|t@r|jd|t@r(|jd|t@r:|jd|t@rL|jd|t@r^|jd|t@rp|jd|t@r|jd|t@r|jdd j |S) NZFINZSYNZRSTZPSHZACKZURGZECEZCWR|) TCPHDR_FINappend TCPHDR_SYN TCPHDR_RST TCPHDR_PSH TCPHDR_ACK TCPHDR_URG TCPHDR_ECE TCPHDR_CWRjoin)flagsZarrr/usr/lib/python3.6/tcp.py flags2str(s$        rN) Ztcpstaterrrrrrrrrrrrrs*__pycache__/utils.cpython-36.opt-1.pyc000064400000010370152344707330013512 0ustar003 :)g@sddlZddlZddlZddlZddlZddlmZddZddZ dd Z d d Z ej Z ejdfd d ZGdddeZdddZdZddZGdddeZdS)N)libc Csg}t|d|}|j}xl|jdD]^}|jd}|dkrJ|jt|q$t|d|}t||dd}|jt||dq$WWdQRX|S)Nr,-r)openreadsplitfindappendintextendrange)pathZcpusfZcpus_range_strZ cpu_rangeZrangeopstartendr/usr/lib/python3.6/utils.py_read_cpu_ranges  "rcCstdS)Nz/sys/devices/system/cpu/online)rrrrrget_online_cpus$srcCstdS)Nz /sys/devices/system/cpu/possible)rrrrrget_possible_cpus'srcCs.tj|}tj|tjjj}||kr*|SdS)N)rZbcc_procutils_languagectcastZc_char_pvaluedecode)Z candidatespidresZlanguagerrrdetect_language*s rcCs8t|dr|jn|}|j||r,|jd|jdS)zA printb(s) print a bytes object to stdout and flush buffer N)hasattrr writeflush)sfilenlZbufrrrprintb1s   r(c@s(eZdZdZddZddZddZdS) ArgStringz ArgString(arg) encapsulate a system argument that can be easily coerced to a bytes() object, which is better for comparing to kernel or probe data (which should never be en/decode()'ed). cCs&tjddkr||_n |jt|_dS)Nr)sys version_infor%rFILESYSTEMENCODING)selfargrrr__init__FszArgString.__init__cCs |jjtS)N)r%encoder-)r.rrr __bytes__LszArgString.__bytes__cCs|jS)N)r%)r.rrr__str__OszArgString.__str__N)__name__ __module__ __qualname____doc__r0r2r3rrrrr)>sr)cCsDt|dr|ntj}tjtjd|d|jtj|||||dS)Nr#)rr&) r"r+stderr traceback print_stack _getframer#warnings formatwarning)messagecategoryfilenamelinenor&linelogrrrwarn_with_tracebackRsrEFcCs@|dkr |Strn*t|tk rs     __pycache__/utils.cpython-36.pyc000064400000010440152344707330012551 0ustar003 :)g@sddlZddlZddlZddlZddlZddlmZddZddZ dd Z d d Z ej Z ejdfd d ZGdddeZdddZdZddZGdddeZdS)N)libc Csg}t|d|}|j}xl|jdD]^}|jd}|dkrJ|jt|q$t|d|}t||dd}|jt||dq$WWdQRX|S)Nr,-r)openreadsplitfindappendintextendrange)pathZcpusfZcpus_range_strZ cpu_rangeZrangeopstartendr/usr/lib/python3.6/utils.py_read_cpu_ranges  "rcCstdS)Nz/sys/devices/system/cpu/online)rrrrrget_online_cpus$srcCstdS)Nz /sys/devices/system/cpu/possible)rrrrrget_possible_cpus'srcCs.tj|}tj|tjjj}||kr*|SdS)N)rZbcc_procutils_languagectcastZc_char_pvaluedecode)Z candidatespidresZlanguagerrrdetect_language*s rcCs8t|dr|jn|}|j||r,|jd|jdS)zA printb(s) print a bytes object to stdout and flush buffer N)hasattrr writeflush)sfilenlZbufrrrprintb1s   r(c@s(eZdZdZddZddZddZdS) ArgStringz ArgString(arg) encapsulate a system argument that can be easily coerced to a bytes() object, which is better for comparing to kernel or probe data (which should never be en/decode()'ed). cCs&tjddkr||_n |jt|_dS)Nr)sys version_infor%rFILESYSTEMENCODING)selfargrrr__init__FszArgString.__init__cCs |jjtS)N)r%encoder-)r.rrr __bytes__LszArgString.__bytes__cCs|jS)N)r%)r.rrr__str__OszArgString.__str__N)__name__ __module__ __qualname____doc__r0r2r3rrrrr)>sr)cCsDt|dr|ntj}tjtjd|d|jtj|||||dS)Nr#)rr&) r"r+stderr traceback print_stack _getframer#warnings formatwarning)messagecategoryfilenamelinenor&linelogrrrwarn_with_tracebackRsrEFcCsX|dkr |Str*t|tksTtd|n*t|tk rTtjd|tdt|jS|S)Nznot a bytes object: %rr8) _strict_bytestypebytesAssertionErrorr=warnDeprecationWarningr)r2)r/rrr_assert_is_bytes[s  rLc@s$eZdZeddZeddZdS) StrcmpRewritecCs"d|}|d|||f7}||fS)Nzstreq_%da~ static inline bool %s(char const *ignored, uintptr_t str) { char needle[] = %s; char haystack[sizeof(needle)]; %s(&haystack, sizeof(haystack), (void *)str); for (int i = 0; i < sizeof(needle) - 1; ++i) { if (needle[i] != haystack[i]) { return false; } } return true; } r)stringprobe_read_funcstreq_functionsprobeidfnamerrr_generate_streq_functionfs z&StrcmpRewrite._generate_streq_functionc Cs|r d}nd}tj||}x^|D]V}|jd} d} |sH|jdj|krLd} tj| | ||\} }|d7}|jd| d}q W|||d} | S) NzSTRCMP\("([^"]+)\",(.+?)\)zSTRCMP\(("[^"]+\"),(.+?)\)rZbpf_probe_readr8Zbpf_probe_read_userZSTRCMP)exprrPrQ)refinditergroupstriprMrSreplace) rTZbin_cmpZis_userZprobe_user_listrPrQZ STRCMP_REZmatchesmatchrNrOrRZrdictrrr rewrite_exprys&    zStrcmpRewrite.rewrite_exprN)r4r5r6 staticmethodrSr[rrrrrMes rM)NN)Zctypesrr+r:r=rUZlibbccrrrrrgetfilesystemencodingr-stdoutr(objectr)rErFrLrMrrrrs     __pycache__/version.cpython-36.pyc000064400000000206152344707330013075 0ustar003 :)g@sdZdS)z0.25.0N) __version__rr/usr/lib/python3.6/version.pys__pycache__/libbcc.cpython-36.opt-1.pyc000064400000020047152344707330013572 0ustar003 :)g8 @s2 ddlZejdddZddlmZejej_ej ej ej ej ej ej ej gej_ejej_ej ej ej ej ej ej ej gej_ej ej_dej_dej_ejgej_ej ej_ejgej_ej ej_ejgej_ejej_ejgej_ej ej_ejejgej_ejej_ejej gej_ejej_ejej gej_ejej_ejej gej_ej ej_ejej gej_ej ej_ejejgej_ejej_ejejgej_ej ej_ejejgej_ej ej_ejej gej_ej ej _ejej gej _ej ej!_ejejej ejejgej!_ej ej"_ejejej ejejgej"_ej ej#_ejejej ejgej#_ej ej$_ejejej ejgej$_ejej%_ejej gej%_ej ej&_ejej ejgej&_ej ej'_ej ejejgej'_ej ej(_ej ejej gej(_ej ej)_ej ejejgej)_ej ej*_ej ejejejgej*_ej ej+_ej ejgej+_ej ej,_ej ejejgej,_ej ej-_ej ejejej ej.gej-_ej ej/_ej ej ej.ej ej.ejejejgej/_ej ej0_ej ej ej.ej ej.ejejejgej0_ej ej1_ej gej1_ej ej2_ej ej gej2_ej ej3_ejej ej ejejej ej ej ej ej ej ej g ej3_ej4dej5ejej Z6ej4dej5ejZ7ej ej8_ej ej ej ej ejej gej8_ej ej9_ej gej9_ej ej:_ej ej ej ej ejej gej:_ej ej;_ej gej;_ej ej<_ej ej ej gej<_ej ej=_ej ej gej=_ej ej>_ej ej gej>_ej ej?_ej gej?_ej ej@_ej gej@_ej ejA_ej ej ej ej gejA_Bej ejC_ej ej ej gejC_Bej ejD_dejD_ej ejE_ej ej gejE_ejejF_e6e7ej5ej ej ej gejF_GdddejGZHejejI_e6e7ej5ej ej eHgejI_ej ejJ_ej ejej ej gejJ_ej ejK_ej ej ejej gejK_ej ejL_ej ej ejgejL_dejM_ejgejM_eNejO_ejgejO_ej ejP_ej ej ej gejP_ej ejQ_ej ej ej ejejej ej ej gejQ_Bej ejR_ejSej ej ej ej gejR_Bej ejT_ej gejT_Bej4ej ejejej ZUejejV_ej eUejgejV_dejW_ejgejW_ej ejX_ejej eUejgejX_ej ejY_ejej gejY_ej ejZ_ejgejZ_Gd d d ejGZ[Gd d d ej\Z]Gd ddejGZ^GdddejGZ_ej ej`eja_ej ej geja_dejb_ejgejb_ej ej`ejc_ej gejc_ej ejd_ej ej ejej ej e_ej e[gejd_ej4ej ej ejZeej ejf_ej eegejf_ejejg_ej ej e_gejg_ejejh_ejej gejh_ejeji_deji_dejj_ejgejj_ej ejk_ejej gejk_ej ejl_ejej e^ej e[gejl_ejejm_ej e[gejm_ej ejn_ejejej e[gejn_ej ejo_ejejej e[gejo_ej ejp_ejej ej ej ejgejp_dejq_ejgejq_ej ejr_dejr_ejejs_ej ej gejs_ejejt_ej gejt_deju_ejgeju_ej ejv_ejej ej gejv_ej ejw_ejej ej ej gejw_ej ejx_ej ejej gejx_ej ejy_ejej ej gejy_ej ejz_ejej ej ej gejz_GdddejGZ{GdddejGZ|Gddde}Z~GdddejGZej4dej e{Zdej_ejegej_ej ej_ejej ej ej ej e|gej_ej ej_ejej ej ej ej ej egej_ej4dej ej ejej Zdej_ejegej_dS)Nz libbcc.so.0T)Z use_errno)Perfc@s(eZdZdejfdejfdejfgZdS)bcc_perf_buffer_optspidZcpuZ wakeup_eventsN)__name__ __module__ __qualname__ctc_int_fields_r r /usr/lib/python3.6/libbcc.pyrsrc@s6eZdZdejfdejfdejejfdejfgZdS) bcc_symbolnameZ demangle_namemoduleoffsetN) rrrr c_char_pPOINTERc_char c_ulonglongr r r r r rsrc@s eZdZdejfdejfgZdS)bcc_ip_offset_unionrZipN)rrrr Zc_uint64r r r r r rsrc@s*eZdZdejfdejdfdefgZdS)bcc_stacktrace_build_idZstatusZbuild_iduN)rrrr c_uint32Zc_ubyterr r r r r rs rc@s0eZdZdejfdejfdejfdejfgZdS)bcc_symbol_optionZuse_debug_fileZcheck_debug_file_crcZlazy_symbolizeZuse_symbol_typeN)rrrr r c_uintr r r r r rsrc@s@eZdZdejfdejfdejfdejfdejfdejfgZdS)bcc_usdtZproviderrbin_pathZ semaphoreZ num_locationsZ num_argumentsN)rrrr rrr r r r r r r"s rc@s eZdZdejfdejfgZdS)bcc_usdt_locationZaddressrN)rrrr rrr r r r r r,src@s(eZdZdZdZdZdZdZdZdZ dS) BCC_USDT_ARGUMENT_FLAGSrr N) rrrZNONEZCONSTANTZ DEREF_OFFSETZ DEREF_IDENTZBASE_REGISTER_NAMEZINDEX_REGISTER_NAMEZSCALEr r r r r 2sr c @sPeZdZdejfdejfdejfdejfdejfdejfdejfdejfgZd S) bcc_usdt_argumentsizeZvalidZconstantZ deref_offsetZ deref_identZbase_register_nameZindex_register_nameZscaleN)rrrr r Z c_longlongrr r r r r r&;sr&)Zctypesr ZCDLLlibZperfrZc_void_pZbpf_module_create_cZrestyperrrr Zc_boolZargtypesZbpf_module_create_c_from_stringZbpf_module_rw_engine_enabledZbpf_module_destroyZbpf_module_licenseZbpf_module_kern_versionrZbpf_num_functionsZbpf_function_nameZbpf_function_startZc_size_tZbpf_function_sizeZ bpf_table_idZ bpf_table_fdZbpf_table_type_idZbpf_table_max_entries_idZbpf_table_flags_idZbpf_table_key_descZbpf_table_leaf_descZbpf_table_key_snprintfZbpf_table_leaf_snprintfZbpf_table_key_sscanfZbpf_table_leaf_sscanfZbpf_perf_event_fieldsZbpf_perf_event_fieldZbpf_get_next_keyZbpf_get_first_keyZbpf_lookup_elemZbpf_update_elemZbpf_delete_elemZbpf_delete_batchZbpf_update_batchrZbpf_lookup_batchZbpf_lookup_and_delete_batchZbpf_open_raw_sockZbpf_attach_socketZ bcc_func_loadZ CFUNCTYPEZ py_objectZ _RAW_CB_TYPEZ _LOST_CB_TYPEZbpf_attach_kprobeZbpf_detach_kprobeZbpf_attach_uprobeZbpf_detach_uprobeZbpf_attach_tracepointZbpf_detach_tracepointZbpf_attach_raw_tracepointZbpf_attach_kfuncZbpf_attach_lsmZbpf_prog_attachZargtypeZbpf_prog_detach2Zbpf_has_kernel_btfZkernel_struct_has_fieldZbpf_open_perf_bufferZ StructurerZbpf_open_perf_buffer_optsZbpf_open_perf_eventZperf_reader_pollZperf_reader_consumeZperf_reader_freeintZperf_reader_fdZbpf_attach_xdpZbpf_attach_perf_eventZbpf_attach_perf_event_rawZperf_event_attrZbpf_close_perf_event_fdZ_RINGBUF_CB_TYPEZbpf_new_ringbufZbpf_free_ringbufZbpf_add_ringbufZbpf_poll_ringbufZbpf_consume_ringbufrZUnionrrrrZbcc_procutils_which_soZbcc_procutils_freeZbcc_procutils_languageZbcc_resolve_symnameZ _SYM_CB_TYPEZbcc_foreach_function_symbolZbcc_symcache_newZbcc_free_symcacheZbcc_buildsymcache_newZbcc_free_buildsymcacheZbcc_buildsymcache_add_moduleZbcc_buildsymcache_resolveZbcc_symbol_free_demangle_nameZbcc_symcache_resolveZ bcc_symcache_resolve_no_demangleZbcc_symcache_resolve_nameZbcc_symcache_refreshZbcc_free_memoryZbcc_usdt_new_frompidZbcc_usdt_new_frompathZbcc_usdt_closeZbcc_usdt_enable_probeZ%bcc_usdt_enable_fully_specified_probeZbcc_usdt_genargsZbcc_usdt_get_probe_argctypeZ+bcc_usdt_get_fully_specified_probe_argctyperrobjectr r&Z_USDT_CBZbcc_usdt_foreachZbcc_usdt_get_locationZbcc_usdt_get_argumentZ_USDT_PROBE_CBZbcc_usdt_foreach_uprober r r r s                                           (                                      (                            __pycache__/__init__.cpython-36.opt-1.pyc000064400000152070152344707330014115 0ustar003 :)gh @sddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z mZmZmZmZddlmZmZmZmZmZddlmZddlmZmZmZmZmZddl m!Z!dd l"m#Z#m$Z$dd l%m&Z&m'Z'ye(Wne)k re*Z(YnXd Z+da,d d Z-dZ.dZ/dZ0dZ1dZ2dZ3dZ4Gddde5Z6GdddZ7GdddZ8GdddZ9GdddZ:GdddZ;Gd d!d!ZGd&d'd'e5Z?dS)()print_functionN)lib bcc_symbolbcc_symbol_optionbcc_stacktrace_build_id _SYM_CB_TYPE)TablePerfEventArrayRingBufBPF_MAP_TYPE_QUEUEBPF_MAP_TYPE_STACK)Perf)get_online_cpusprintb_assert_is_bytes ArgString StrcmpRewrite) __version__)disassemble_prog decode_map)USDT USDTExceptionicCstS)N)_num_open_probesrr/usr/lib/python3.6/__init__.py_get_num_open_probes+srz/sys/kernel/debug/tracing c@s$eZdZddZddZddZdS) SymbolCachecCs tj|tjdtjt|_dS)N)rZbcc_symcache_newctcastPOINTERrcache)selfpidrrr__init__AszSymbolCache.__init__cCst}|r"tj|j|tj|}ntj|j|tj|}|dkrp|jrf|jrfd|jtj |jtj j fSd|dfS|r|j }tj tj|n|j}||jtj |jtj j fS)a Return a tuple of the symbol (function), its offset from the beginning of the function, and the module in which it lies. For example: ("start_thread", 0x202, "/usr/lib/.../libpthread-2.24.so") If the symbol cannot be found but we know which module it is in, return the module name and the offset from the beginning of the module. If we don't even know the module, return the absolute address as the offset. rN)rrZbcc_symcache_resolver&r#byrefZ bcc_symcache_resolve_no_demanglemoduleoffsetr$c_char_pvalueZ demangle_nameZbcc_symbol_free_demangle_namename)r'addrdemanglesymresZname_resrrrresolveEs     zSymbolCache.resolvecCs>t|}t|}tj}tj|j||tj|dkr8dS|jS)Nrr)rr# c_ulonglongrZbcc_symcache_resolve_namer&r*r.)r'r+r/r0rrr resolve_namebs zSymbolCache.resolve_nameN)__name__ __module__ __qualname__r)r4r7rrrrr"@sr"c@s$eZdZdZdZdZdZdZdZdS)PerfTyperrrrN) r8r9r:ZHARDWAREZSOFTWARE TRACEPOINTZHW_CACHERAWZ BREAKPOINTrrrrr;ks r;c@s4eZdZdZdZdZdZdZdZdZ dZ d Z d Z d S) PerfHWConfigrrrr<rr=r N) r8r9r:Z CPU_CYCLESZ INSTRUCTIONSZCACHE_REFERENCESZ CACHE_MISSESZBRANCH_INSTRUCTIONSZ BRANCH_MISSESZ BUS_CYCLESZSTALLED_CYCLES_FRONTENDZSTALLED_CYCLES_BACKENDZREF_CPU_CYCLESrrrrr@tsr@c@s8eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d S) PerfSWConfigrrrr<rr=rArBrrC N)r8r9r:Z CPU_CLOCKZ TASK_CLOCKZ PAGE_FAULTSZCONTEXT_SWITCHESZCPU_MIGRATIONSZPAGE_FAULTS_MINZPAGE_FAULTS_MAJZALIGNMENT_FAULTSZEMULATION_FAULTSZDUMMYZ BPF_OUTPUTrrrrrDsrDc@speZdZdZdZdZdZdZd Zd!Z d"Z d#Z d$Z d%Z d&Zd'Zd(Zd)Zd*Zd+Zd,Zd-Zd.Zd/Zd0Zd1Zd2Zd3ZdS)4PerfEventSampleFormatrrrr<rr=rArBrrCrE r Nrrrrr r!@iiiii i@iiiiiii i@ii)r8r9r:ZIPZTIDZTIMEZADDRZREADZ CALLCHAINZIDZCPUZPERIODZ STREAM_IDr?Z BRANCH_STACKZ REGS_USERZ STACK_USERZWEIGHTZDATA_SRCZ IDENTIFIERZ TRANSACTIONZ REGS_INTRZ PHYS_ADDRZAUXZCGROUPZDATA_PAGE_SIZEZCODE_PAGE_SIZEZ WEIGHT_STRUCTrrrrrFs2rFc@s`eZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdS) BPFProgTyperrr<rr=rArBrrCrErGrHrIrJrKr rLrMN)r8r9r: SOCKET_FILTERKPROBE SCHED_CLS SCHED_ACTr>XDP PERF_EVENT CGROUP_SKB CGROUP_SOCKLWT_INLWT_OUTLWT_XMITSOCK_OPSSK_SKB CGROUP_DEVICESK_MSGRAW_TRACEPOINTCGROUP_SOCK_ADDRZCGROUP_SOCKOPTTRACINGLSMrrrrrWs*rWc@seZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!d Z"d!Z#d"Z$d#Z%d$Z&d%Z'd&Z(d'Z)d(S)) BPFAttachTyperrrr<rr=rArBrrCrErGrHrIrJrKr rLrMrNrOrPrQrRrSrXrYrZr!!"#$%&N)*r8r9r:ZCGROUP_INET_INGRESSZCGROUP_INET_EGRESSZCGROUP_INET_SOCK_CREATEZCGROUP_SOCK_OPSZSK_SKB_STREAM_PARSERZSK_SKB_STREAM_VERDICTrhZSK_MSG_VERDICTZCGROUP_INET4_BINDZCGROUP_INET6_BINDZCGROUP_INET4_CONNECTZCGROUP_INET6_CONNECTZCGROUP_INET4_POST_BINDZCGROUP_INET6_POST_BINDZCGROUP_UDP4_SENDMSGZCGROUP_UDP6_SENDMSGZ LIRC_MODE2ZFLOW_DISSECTORZ CGROUP_SYSCTLZCGROUP_UDP4_RECVMSGZCGROUP_UDP6_RECVMSGZCGROUP_GETSOCKOPTZCGROUP_SETSOCKOPTZ TRACE_RAW_TPZ TRACE_FENTRYZ TRACE_FEXITZ MODIFY_RETURNZLSM_MACZ TRACE_ITERZCGROUP_INET4_GETPEERNAMEZCGROUP_INET6_GETPEERNAMEZCGROUP_INET4_GETSOCKNAMEZCGROUP_INET6_GETSOCKNAMEZ XDP_DEVMAPZCGROUP_INET_SOCK_RELEASEZ XDP_CPUMAPZ SK_LOOKUPr_ZSK_SKB_VERDICTrrrrrnsNrnc@s eZdZdZdZdZdZdZdS) XDPActionrrrr<rN)r8r9r: XDP_ABORTEDXDP_DROPXDP_PASSXDP_TX XDP_REDIRECTrrrrrys ryc@s eZdZdZdZd Zd Zd ZdS) XDPFlagsrrrr<rNrrrrr )r8r9r:UPDATE_IF_NOEXISTSKB_MODEDRV_MODEHW_MODEREPLACErrrrrs rc@seZdZejZejZejZejZejZej Z ej Z ej Z ej Z ej Z ejZejZejZejZejZejZejZejZejZejZejZejZejZejZejZejZ ej!Z"ej#Z$ej%Z&ej'Z(e)j*dZ+iZ,e-j.Z/dgddgddgdgdd gd Z0d d d ddddgZ1dZ2Gddde3j4Z5e3j6dddZ7e7j8Z9e3j:e3j;e5ge9_e=ddZ?e@Z@GdddeAZBeCddZDeCd d!ZEd"d"d#d$ggdd#d%f d&d'ZFefd(d)ZGdd*d+ZHd,d-ZId.d/ZJdd0d1ZKe3jLe3jMe3jNe3jOe3jPe3jQe3j:e3jRe3jSe3jTe3jUe3jVe3jWe3jXe3jYe3jZd2e3j[d2d3Z\eCd4d5Z]dd6d7Z^d8d9Z_d:d;Z`dd?Zbd@dAZceCddBdCZdeCdDdEZeeCdFdGZfeCdHdIZgdJdKZheCdLdMZidNdOZjdPdQZkdRdSZldTdUZmdVdWZndXdYZodZd[Zpdd\d]Zqdd^d_Zrd`daZsdbdcZtddddeZuddfdgZveCddhdiZweCddjdkZxe=ddldmZyeCdndoZzeCdpdqZ{eCdrdsZ|ddtduZ}ddvdwZ~ddxdyZeCdzd{ZeCd|d}ZeCd~dZdddZdddZdddZdddZdddZdddZeCddZeCddZeCddZdddZddZdddZddZdddZdddZeCddZeCddZeCddZddZdddZd ddZddZd ddZd ddZddZdddZdddZdddZdddZeCddZeCdddZeCdddZeCddZddÄZddńZddDŽZdddɄZdd˄Zddd̈́ZdddτZdddфZddӄZddՄZeCddׄZddلZddۄZdd݄Zdd߄ZddZd#S(BPFs [^a-zA-Z0-9_]ZtimeZfsfileZbioZrequestZallocZsk_buffZ net_device)z linux/time.hz linux/fs.hzlinux/blkdev.hz linux/slab.hzlinux/netdevice.hssys_s __x64_sys_s__x32_compat_sys_s__ia32_compat_sys_s __arm64_sys_s __s390x_sys_s __s390_sys_rc@s eZdZdejfdejfgZdS)z BPF.timespectv_sectv_nsecN)r8r9r:r#c_long_fields_rrrrtimespec@srz librt.so.1T)Z use_errnocCsH|j}|j|jtj|dkr8tj}t|tj||j d|j S)zmonotonic_time() Returns the system monotonic time from clock_gettime, using the CLOCK_MONOTONIC constant. The time returned is in nanoseconds. rgeA) r_clock_gettimeCLOCK_MONOTONICr#r* get_errnoOSErrorosstrerrorrr)clsterrnorrrmonotonic_timeGs zBPF.monotonic_timecCsXd}xN|jjD]@\}}x6|D].}x(|D] }||kr(||kr(|d|7}q(WqWqW|S)a1 Generates #include statements automatically based on a set of recognized types such as sk_buff and bio. The input is all the words that appear in the BPF program, and the output is a (possibly empty) string of #include statements, such as "#include ". z#include <%s> )_auto_includesitems)rZ program_wordsZheadersheaderkeywordskeywordZwordrrrgenerate_auto_includesSs  zBPF.generate_auto_includesc@seZdZddZdS)z BPF.FunctioncCs||_||_||_dS)N)bpfr/fd)r'rr/rrrrr)gszBPF.Function.__init__N)r8r9r:r)rrrrFunctionfsrcCsb|r^tjj|s^ttjd}djtjjtjj|j |g}tjj|rR|}n t d||S)z1 If filename is invalid, search in ./ of argv[0] r/zCould not find file %s) rpathisfilersysargvjoinabspathdirname __bytes__ Exception)filenameZargv0rrrr _find_filels "  zBPF._find_filecCsrdd}tjj|\}}|r*||rn|SnDxBtjdjtjD],}|jd}tjj|j|}||r>|Sq>WdS)a find_exe(bin_path) Traverses the PATH environment variable, looking for the first directory that contains an executable file named bin_path, and returns the full path to that file, or None if no such file can be found. This is meant to replace invocations of the "which" shell utility, which doesn't have portable semantics for skipping aliases. cSstjj|otj|tjS)N)rrraccessX_OK)fpathrrris_exes zBPF.find_exe..is_exePATH"N)rrsplitenvironpathsepstriprencode)Zbin_pathrrZfnamerZexe_filerrrfind_exeys  z BPF.find_exeNrFc Cst|}t|}t|}i|_i|_i|_i|_i|_i|_i|_i|_i|_ d|_ d|_ t j |j||_i|_i|_d|_tjt|} x$t|D]\} } tt| | | <qW|rtj|}tj|}|rt|dd} | j}WdQRXtjt|}x(t|D]\} }tj|j|| <q Wtj |t|}|dkrLt!d ||}tj"||j| t| |||_|jst!d|pd x|D]}|j#|| qW|j$dS) aZCreate a new BPF module with the given source code. Note: All fields are marked as optional, but either `src_file` or `text` must be supplied, and not both. Args: src_file (Optional[str]): Path to a source file for the module hdr_file (Optional[str]): Path to a helper header file for the `src_file` text (Optional[str]): Contents of a source file for the module debug (Optional[int]): Flags used for debug prints, can be |'d together See "Debug flags" for explanation Nrb)modez%can't generate USDT probe arguments; z%possible cause is missing pid when a z&probe in a shared object has multiple Z locationszFailed to compile BPF module %szzJcan't generate USDT probe arguments; possible cause is missing pid when a zpcan't generate USDT probe arguments; possible cause is missing pid when a probe in a shared object has multiple zycan't generate USDT probe arguments; possible cause is missing pid when a probe in a shared object has multiple locations)%r kprobe_fds uprobe_fdstracepoint_fdsraw_tracepoint_fdskfunc_entry_fdskfunc_exit_fdslsm_fds perf_buffersopen_perf_events_ringbuf_manager tracefileatexitregistercleanupdebugfuncstablesr+r#r-len enumeratebytesrrropenreadc_void_pZ get_contextrZbcc_usdt_genargsrZbpf_module_create_c_from_stringZattach_uprobes_trace_autoload)r'Zsrc_fileZhdr_filetextrZcflagsZ usdt_contextsZ allow_rlimitdeviceZattach_usdt_ignore_pidZ cflags_arrayisrZ ctx_arrayusdtZ usdt_textZ usdt_contextrrrr)s\      z BPF.__init__cCsDg}x:tdtj|jD]$}tj|j|}|j|j||qW|S)zload_funcs(prog_type=KPROBE) Load all functions in this BPF module with the given type. Returns a list of the function handles.r)rangerbpf_num_functionsr+bpf_function_nameappend load_func)r' prog_typefnsr func_namerrr load_funcss zBPF.load_funcsc Cst|}||jkr|j|Stj|j|s6td|d}|jt@rJd}n|jt@rXd}tj |j||tj|j|tj |j|tj |jtj |j|dd|| }|dkrt j|jtjtjkrtdtjtj}td||ftj|||}||j|<|S)NzUnknown program %srrrz!Need super-user privileges to runz!Failed to load BPF program %s: %s)rrrbpf_function_startr+rrDEBUG_BPF_REGISTER_STATE DEBUG_BPFZ bcc_func_loadbpf_function_sizeZbpf_module_licenseZbpf_module_kern_versionrr donothingr#rrEPERMrrrr) r'rrr attach_typeZ log_levelrerrstrfnrrrrs4             z BPF.load_funccCsJt|}tj|j|s"td|tj|j|}tj|j|}tj||S)zR Return the eBPF bytecodes for the specified function as a string zUnknown program %s)rrrr+rrr#Z string_at)r'rstartsizerrr dump_funcs  z BPF.dump_funccCs|j|}t||S)N)rr)r'rZbpfstrrrrdisassemble_funcs zBPF.disassemble_funccCs(||}tj|j|j}t||||dS)N)sizeinfo)rbpf_table_type_idr+map_idr)r'Z table_namerZ table_objZ table_typerrr decode_table#szBPF.decode_tabler)Z_BoolcharZwchar_tz unsigned charZshortzunsigned shortintz unsigned intZlongz unsigned longz long longzunsigned long longfloatZdoublez long doubleZ__int128zunsigned __int128cCst|trtj|Sg}g}xN|dD]@}t|dkrX|j|dtj|dfq(t|dkrZt|dtr|j|dtj|d|ddfnt|dtr|j|dtj|d|dfnt|dtrH|ddks |ddks |ddkrH|d}|dkr2d t|}|j||j|tj|fnt d t |q(t d t |q(Wt j }d }t|dkr|ddkrt j }n.|ddkrt j }n|ddkrt j }d }|rtt |d|ft|d|d }ntt |d|ft||d}|S)Nrrrr<unionstructZ struct_packedrz__anon%dzFailed to decode type %sFT) _anonymous_Z_pack_r)rr) isinstance basestringr str2ctyperr_decode_table_typelistrrstrr# StructureZUniontypedict)ZdescZanonfieldsrr/baseZ is_packedrrrrr;sL   *$     zBPF._decode_table_typec Cst|}tj|j|}tj|j|}tj|j|ttgk}|dkrFt| r| rtj |j|j d}|svt d|t j tj|}|stj|j|j d} | st d|t j tj| }t|||||||dS)Nrzutf-8z$Failed to load BPF Table %s key descz%Failed to load BPF Table %s leaf desc)reducer)rrZ bpf_table_idr+Z bpf_table_fdrr r KeyErrorZbpf_table_key_descdecoderrrjsonloadsZbpf_table_leaf_descr ) r'r/ZkeytypeZleaftyperrmap_fdZ is_queuestackZkey_descZ leaf_descrrr get_tablegs"   z BPF.get_tablecCs$||jkr|j||j|<|j|S)N)rr )r'keyrrr __getitem__zs zBPF.__getitem__cCs||j|<dS)N)r)r'r Zleafrrr __setitem__szBPF.__setitem__cCs t|jS)N)rr)r'rrr__len__sz BPF.__len__cCs |j|=dS)N)r)r'r rrr __delitem__szBPF.__delitem__cCs |jjS)N)r__iter__)r'rrrrsz BPF.__iter__cCsJt|tjstdtj|j|||}|dkrFtdj|tj | dS)Nz"arg 1 must be of type BPF.Functionrz7Failed to attach BPF function with attach_type {0}: {1}) rrrrrZbpf_prog_attachrformatrr)r attachable_fdrflagsr3rrr attach_funcs  zBPF.attach_funccCsHt|tjstdtj|j||}|dkrDtdj|tj | dS)Nz"arg 1 must be of type BPF.Functionrz7Failed to detach BPF function with attach_type {0}: {1}) rrrrrZbpf_prog_detach2rrrr)rrrr3rrr detach_funcs  zBPF.detach_funccCst|}t|tjstdtj|}|dkrLtjt j }td||ftj ||j }|dkrtjt j }td||f||_ dS)Nz"arg 1 must be of type BPF.Functionrz Failed to open raw device %s: %sz%Failed to attach BPF to device %s: %s)rrrrrrZbpf_open_raw_sockrrr#rZbpf_attach_socketrsock)rdevrrr3rrrattach_raw_sockets   zBPF.attach_raw_socketc Csdt}y,t|d}tdd|D}WdQRXWn:tk rn}z|jtjkrV|tg}WYdd}~XnXg}d}d}tdd}x |D]} | jjdd\} } |dkr| d krd}qn|dkr| d krd }q|dkr | d krd}qn| d kr"d }qn|dkr"| d krd }q| jdr2qn:| jds| jdrLqn | jdr\qnt j d| rlq| j dkrt j || r| |kr|j | qWWdQRXt|S)Nz%s/../kprobes/blacklistrcSsg|]}|jjdqS)r)rstripr).0linerrr sz,BPF.get_kprobe_functions..rz/proc/kallsymsrr<s __init_begins __init_endrs__irqentry_text_starts__irqentry_text_ends _kbl_addr_s__perfsperf_s__SCT__s^.*\.cold(\.\d+)?$tw)rr)TRACEFSrsetIOErrorrrrr startswithrematchlower fullmatchr) event_reZblacklist_fileZ blacklist_fZ blacklisterZin_init_sectionZin_irq_sectionZ avail_filerrrrrrget_kprobe_functionssZ        zBPF.get_kprobe_functionscCst|tjkrtddS)Nz/Number of open probes would exceed global quota)rrget_probe_limitr)r'Znum_new_probesrrr_check_probe_quotaszBPF._check_probe_quotacCs(tjjd}|r |jr t|StSdS)NZBCC_PROBE_LIMIT)rrgetisdigitr_default_probe_limit)Zenv_probe_limitrrrr)s  zBPF.get_probe_limitcCs.||jkri|j|<||j||<td7adS)Nr)rr)r'ev_namefn_namerrrr_add_kprobe_fds  zBPF._add_kprobe_fdcCs|j||=td8adS)Nr)rr)r'r.r/rrr_del_kprobe_fds zBPF._del_kprobe_fdcCs||j|<td7adS)Nr)rr)r'r/rrrr_add_uprobe_fd s zBPF._add_uprobe_fdcCs|j|=td8adS)Nr)rr)r'r/rrr_del_uprobe_fdszBPF._del_uprobe_fdcCs0x$|jD]}|jd|dkr|SqW|jdS)Ns%sbpfrrr5)_syscall_prefixesksymname)r'prefixrrrget_syscall_prefixs zBPF.get_syscall_prefixcCst|}|j|S)N)rr7)r'r/rrrget_syscall_fnname szBPF.get_syscall_fnnamecCs<t|}x.|jD]$}|j|r|j|t|dSqW|S)N)rr4r!r8r)r'r/r6rrrfix_syscall_fnname's   zBPF.fix_syscall_fnnamec Cst|}t|}t|}|rtj|}|jt|d}g}x>|D]6}y|j||dWqB|d7}|j|YqBXqBW|t|krtd|dj|fdS|jd|j |tj } d|j ddj d d} t j | jd| ||d} | dkrtd||f|j| || |S) Nr)eventr/rzwFailed to attach BPF program %s to kprobe %s, it's not traceable (either non-existing, inlined, or marked as "notrace")/sp_+_.)rrr(r*r attach_kproberrrrr\replacerbpf_attach_kproberr0) r'r:Z event_offr/r&matchesfailedprobesrrr.rrrrr?.s6      zBPF.attach_kprobec Cst|}t|}t|}|rtj|}d}g}x@|D]8}y|j|||dWq4|d7}|j|Yq4Xq4W|t|krtd|dj|fdS|jd|j |tj } d|j ddj d d} t j | jd| |d|} | dkrtd||f|j| || |S) Nr)r:r/ maxactiverzzFailed to attach BPF program %s to kretprobe %s, it's not traceable (either non-existing, inlined, or marked as "notrace")r;sr_r<r=r>)rrr(attach_kretproberrrrr*rr\r@rrArr0) r'r:r/r&rErBrCrDrrr.rrrrrFPs6      zBPF.attach_kretprobecCs8t|}t|j|j}x|D]}|j||q WdS)N)rrrkeysdetach_kprobe_event_by_fn)r'r.Zfn_namesr/rrrdetach_kprobe_eventrs zBPF.detach_kprobe_eventcCst|}t|}||jkr&td|tj|j||}|dkrJtd|j||t|j|dkrtj|}|dkrtddS)NzKprobe %s is not attachedrzFailed to close kprobe FDz Failed to detach BPF from kprobe)rrrrbpf_close_perf_event_fdr1rZbpf_detach_kprobe)r'r.r/r3rrrrHxs    zBPF.detach_kprobe_event_by_fncCsHt|}d|jddjdd}|r:t|}|j||n |j|dS)Nsp_r<r=r>)rr@rHrI)r'r:r/r.rrr detach_kprobes zBPF.detach_kprobecCsHt|}d|jddjdd}|r:t|}|j||n |j|dS)Nsr_r<r=r>)rr@rHrI)r'r:r/r.rrrdetach_kretprobes zBPF.detach_kretprobecCsnt|}t|tjstdtj||j|}|dkrjtj }|t j krPtdnt j |}td||fdS)zt This function attaches a BPF function to a device on the device driver level (XDP) z"arg 1 must be of type BPF.Functionrz-Internal error while attaching BPF to device,z try increasing the debug level!z%Failed to attach BPF to device %s: %sNzMInternal error while attaching BPF to device, try increasing the debug level!)rrrrrrbpf_attach_xdprr#rrZEBADMSGrr)rrrr3Zerr_norrrr attach_xdps   zBPF.attach_xdpcCs@t|}tj|d|}|dkrqxRtj|D]D}tjj||}tjj|rJd||f}tj|j|rJ|j |qJWqW|S)Neventsz%s:%s) rrrrlistdirisdirr"r#rr)tp_reresultsZ events_dircategoryZcat_dirr:evt_dirtprrrget_tracepointss   zBPF.get_tracepointscCstjjtd||}tjj|S)NrT)rrrrrV)rYr:rZrrrtracepoint_existsszBPF.tracepoint_existscCst|}t|}t|}|rBx tj|D]}|j||dq(WdS|j|tj}|jd\}}tj|j ||}|dkrt d||f||j |<|S)aattach_tracepoint(tp="", tp_re="", fn_name="") Run the bpf function denoted by fn_name every time the kernel tracepoint specified by 'tp' is hit. The optional parameters pid, cpu, and group_fd can be used to filter the probe. The tracepoint specification is simply the tracepoint category and the tracepoint name, separated by a colon. For example: sched:sched_switch, syscalls:sys_enter_bind, etc. Instead of a tracepoint name, a regular expression can be provided in tp_re. The program will then attach to tracepoints that match the provided regular expression. To obtain a list of kernel tracepoints, use the tplist tool or cat the file /sys/kernel/debug/tracing/available_events. Examples: BPF(text).attach_tracepoint(tp="sched:sched_switch", fn_name="on_switch") BPF(text).attach_tracepoint(tp_re="sched:.*", fn_name="on_switch") )r[r/N:rz0Failed to attach BPF program %s to tracepoint %s) rrr\attach_tracepointrr>rrZbpf_attach_tracepointrrr)r'r[rWr/r tp_categorytp_namerrrrr_s  zBPF.attach_tracepointcCs`t|}||jkrtd|t|}|j|tj}tj|j|}|dkrRtd||j|<|S)aattach_raw_tracepoint(self, tp=b"", fn_name=b"") Run the bpf function denoted by fn_name every time the kernel tracepoint specified by 'tp' is hit. The bpf function should be loaded as a RAW_TRACEPOINT type. The fn_name is the kernel tracepoint name, e.g., sched_switch, sys_enter_bind, etc. Examples: BPF(text).attach_raw_tracepoint(tp="sched_switch", fn_name="on_switch") z#Raw tracepoint %s has been attachedrz&Failed to attach BPF to raw tracepoint) rrrrrrjrZbpf_attach_raw_tracepointr)r'r[r/rrrrrattach_raw_tracepoints    zBPF.attach_raw_tracepointcCs:t|}||jkrtd|tj|j||j|=dS)zdetach_raw_tracepoint(tp="") Stop running the bpf function that is attached to the kernel tracepoint specified by 'tp'. Example: bpf.detach_raw_tracepoint("sched_switch") z!Raw tracepoint %s is not attachedN)rrrrclose)r'r[rrrdetach_raw_tracepoint)s   zBPF.detach_raw_tracepointcCs|j|s||}|S)N)r!)r6r/rrr add_prefix8s zBPF.add_prefixcCs2tjdkrdStjsdStjddkr.dSdS)NZx86_64FZbpf_trampoline_link_progrTr5)platformmachinerbpf_has_kernel_btfrr5rrrr support_kfunc>s zBPF.support_kfunccCs"tjs dStjddkrdSdS)NFs bpf_lsm_bpfrTr5)rrhrr5rrrr support_lsmJs zBPF.support_lsmcCsFt|}tjd|}||jkr*td|tj|j||j|=dS)Nskfunc__z$Kernel entry func %s is not attached)rrrerrrrc)r'r/rrr detach_kfuncSs    zBPF.detach_kfunccCsFt|}tjd|}||jkr*td|tj|j||j|=dS)Ns kretfunc__z#Kernel exit func %s is not attached)rrrerrrrc)r'r/rrrdetach_kretfunc\s    zBPF.detach_kretfunccCsbt|}tjd|}||jkr*td||j|tj}tj|j }|dkrTtd||j|<|S)Nskfunc__z&Kernel entry func %s has been attachedrz)Failed to attach BPF to entry kernel func) rrrerrrrlrbpf_attach_kfuncr)r'r/rrrrr attach_kfunces     zBPF.attach_kfunccCsbt|}tjd|}||jkr*td||j|tj}tj|j }|dkrTtd||j|<|S)Ns kretfunc__z%Kernel exit func %s has been attachedrz(Failed to attach BPF to exit kernel func) rrrerrrrlrrmr)r'r/rrrrrattach_kretfuncss     zBPF.attach_kretfunccCsFt|}tjd|}||jkr*td|tj|j||j|=dS)Nslsm__zLSM %s is not attached)rrrerrrrc)r'r/rrr detach_lsms    zBPF.detach_lsmcCsbt|}tjd|}||jkr*td||j|tj}tj|j }|dkrTtd||j|<|S)Nslsm__zLSM %s has been attachedrzFailed to attach LSM) rrrerrrrmrZbpf_attach_lsmr)r'r/rrrrr attach_lsms     zBPF.attach_lsmcCs$tjddkstjddkr dSdS)NZbpf_find_raw_tracepointrZbpf_get_raw_tracepointTFr5r5)rr5rrrrsupport_raw_tracepointszBPF.support_raw_tracepointc CsZd}t|D}x<|D]4}|jjdd\}}}|jdd}|dkrdSqWdSQRXdS) Nz/proc/kallsyms r rZbpf_trace_modulesTF)rrr)ZkallsymsZsymsr_r/rrr support_raw_tracepoint_in_modules  z$BPF.support_raw_tracepoint_in_modulecCst|}t|}tj||S)N)rrkernel_struct_has_field)Z struct_nameZ field_namerrrrwszBPF.kernel_struct_has_fieldcCstt|}||jkrtd|tj|j|}|dkr>td|jd\}}tj||}|dkrhtd|j|=dS)zdetach_tracepoint(tp="") Stop running a bpf function that is attached to the kernel tracepoint specified by 'tp'. Example: bpf.detach_tracepoint("sched:sched_switch") zTracepoint %s is not attachedrz$Failed to detach BPF from tracepointr^N)rrrrrJrZbpf_detach_tracepoint)r'r[r3r`rarrrdetach_tracepoints    zBPF.detach_tracepointc Cs,tj||||||||} | dkr(td| S)Nrz"Failed to attach BPF to perf event)rZbpf_attach_perf_eventr) r'progfdev_type ev_config sample_period sample_freqr(cpugroup_fdr3rrr_attach_perf_events  zBPF._attach_perf_eventc Cst|}|j|tj} i} |dkrB|j| j|||||||| |<n.x,tD]"} |j| j|||||| || | <qJW| |j||f<dS)Nr)rrrr`rrrr) r'rzr{r/r|r}r(r~rrr3rrrrattach_perf_events   zBPF.attach_perf_eventcCs.tj|tj||||d}|dkr*td|S)Nrz&Failed to attach BPF to perf raw event)rZbpf_attach_perf_event_rawr#r*r)r'ryattrr(r~rr3rrr_attach_perf_event_raws  zBPF._attach_perf_event_rawc Cszt|}|j|tj}i}|dkr<|j|j||||||<n(x&tD]}|j|j||||||<qDW||j|j|j f<dS)Nr) rrrr`rrrrrconfig) r'rr/r(r~rrr3rrrrattach_perf_event_raws   zBPF.attach_perf_event_rawc Cs|y|j||f}Wn$tk r6tdj||YnXd}x|jD]}tj|pV|}qFW|dkrltd|j||f=dS)Nz)Perf event type {} config {} not attachedrz$Failed to detach BPF from perf event)rrrrvaluesrrJ)r'rzr{Zfdsr3rrrrdetach_perf_eventszBPF.detach_perf_eventcCstddtj||DS)NcSsg|] \}}|qSrr)rr/rurrrrsz*BPF.get_user_functions..)rr get_user_functions_and_addresses)r/sym_rerrrget_user_functionsszBPF.get_user_functionscCstddtj||DS)a We are returning addresses here instead of symbol names because it turns out that the same name may appear multiple times with different addresses, and the same address may appear multiple times with the same name. We can't attach a uprobe to the same address more than once, so it makes sense to return the unique set of addresses that are mapped to a symbol that matches the provided regular expression. cSsg|] \}}|qSrr)rruZaddressrrrrsz*BPF.get_user_addresses..)rrr)r/rrrrget_user_addressess zBPF.get_user_addressescsNt|}tgfdd}tj|t|}|dkrJtd||fS)Ncs"|}tj|rj||fdS)Nr)r"r#r)Zsym_namer0Zdname) addressesrrrsym_cbs z4BPF.get_user_functions_and_addresses..sym_cbrz"Error %d enumerating symbols in %s)rrZbcc_foreach_function_symbolrr)r/rrr3r)rrrrsz$BPF.get_user_functions_and_addressescCs>|dkr d||jjd||fSd||jjd|||fSdS)Nrs %s_%s_0x%xr=s %s_%s_0x%x_%dr5) _probe_replsub)r'r6rr0r(rrr_get_uprobe_evname!szBPF._get_uprobe_evnamecCs|dk rt|}t|}t|}t|}|rjtj||}|jt|x|D]} |j|| ||dqLWdStj|||||\} }|jd|j|tj} |j d| ||} t j | j d| | ||} | dkrt d|j| | |S)aattach_uprobe(name="", sym="", sym_re="", addr=None, fn_name="" pid=-1, sym_off=0) Run the bpf function denoted by fn_name every time the symbol sym in the library or binary 'name' is encountered. Optional parameters pid, cpu, and group_fd can be used to filter the probe. If sym_off is given, attach uprobe to offset within the symbol. The real address addr may be supplied in place of sym, in which case sym must be set to its default value. If the file is a non-PIE executable, addr must be a virtual address, otherwise it must be an offset relative to the file load address. Instead of a symbol name, a regular expression can be provided in sym_re. The uprobe will then attach to symbols that match the provided regular expression. Libraries can be given in the name argument without the lib prefix, or with the full path (/usr/lib/...). Binaries can be given only with the full path (/bin/sh). If a PID is given, the uprobe will attach to the version of the library used by the process. Example: BPF(text).attach_uprobe("c", "malloc") BPF(text).attach_uprobe("/usr/bin/python", "main") N)r/r0r/r(rprzFailed to attach BPF to uprobe)rrrr*r attach_uproberRrr\rrbpf_attach_uproberrr2)r'r/r2rr0r/r(rQrsym_addrrrr.rrrrr)s*    zBPF.attach_uprobec Cst|}t|}t|}t|}|rPx&tj||D]}|j||||dq2WdStj||||\}}|jd|j|tj} |jd|||} t j | j d| |||} | dkrt d|j | | |S)a6attach_uretprobe(name="", sym="", sym_re="", addr=None, fn_name="" pid=-1) Run the bpf function denoted by fn_name every time the symbol sym in the library or binary 'name' finishes execution. See attach_uprobe for meaning of additional parameters. )r/r0r/r(Nrrrz!Failed to attach BPF to uretprobe)rrrattach_uretproberRr*rr\rrrrrr2) r'r/r2rr0r/r(rrrr.rrrrrbs$   zBPF.attach_uretprobecCs^||jkrtd|tj|j|}|dkr6tdtj|}|dkrPtd|j|dS)NzUprobe %s is not attachedrz Failed to detach BPF from uprobe)rrrrJZbpf_detach_uprober3)r'r.r3rrrdetach_uprobe_events   zBPF.detach_uprobe_eventcCsDt|}t|}tj|||||\}}|jd|||}|j|dS)zdetach_uprobe(name="", sym="", addr=None, pid=-1) Stop running a bpf function that is attached to symbol 'sym' in library or binary 'name'. rN)rrrRrr)r'r/r2r0r(rQrr.rrr detach_uprobes zBPF.detach_uprobecCsBt|}t|}tj||||\}}|jd|||}|j|dS)zdetach_uretprobe(name="", sym="", addr=None, pid=-1) Stop running a bpf function that is attached to symbol 'sym' in library or binary 'name'. rN)rrrRrr)r'r/r2r0r(rr.rrrdetach_uretprobes zBPF.detach_uretprobecCsnxftdtj|jD]N}tj|j|}|jdrb|j|tj}|j |j |dd|j dq|jdr|j|tj}|j |j |dd|j dq|jdr|j|tj }|j tddjdd }|j||j d q|jd r|j|tj}|j td d}|j||j d q|jd r6|j|d q|jdrP|j|d q|jdr|j|d qWdS)Nrskprobe__r)r:r/s kretprobe__rGs tracepoint__s__r^)r[r/sraw_tracepoint__skfunc__)r/s kretfunc__slsm__)rrrr+rr!rrr\r?r9r/rFr>rr@r_rjrbrnrorq)r'rrrr[rrrrs4         zBPF._trace_autoloadcCsN|jsHtdtd|_|rH|jj}tj|tj}tj|tj|tjB|jS)zWtrace_open(nonblocking=False) Open the trace_pipe if not already open z %s/trace_piper) rrrfilenofcntlZF_GETFLZF_SETFLr O_NONBLOCK)r' nonblockingrZflrrr trace_opens zBPF.trace_openc Csx|j|}| r|rd S|jdr(q|ddj}|dd}|jd}y|d|j\}}}}Wn$tk r} zwWYdd} ~ XnX|dd}||dd}|jd} || dd} y|t|t||t|| fStk r} zdSd} ~ XqXqWdS)ztrace_fields(nonblocking=False) Read from the kernel debug trace pipe and return a tuple of the fields (task, pid, cpu, flags, timestamp, msg) or None if no line was read (nonblocking=True) NrAsCPU:r rLr^rrUnknownr)N)NNNNNNr5)rrrrrr)trace_readliner!lstripfindrrrr) r'rrZtaskZts_endr(r~rZtsr'Zsym_endmsgrrr trace_fieldss*       zBPF.trace_fieldsc Cs:|j|}d}y|jdj}Wntk r4YnX|S)ztrace_readline(nonblocking=False) Read from the kernel debug trace pipe and return one line If nonblocking is False, this will block until ctrl-C is pressed. Ni)rreadlinerr )r'rZtracerrrrrs zBPF.trace_readlinecCsJxD|r$|jdd}|sq|j|}n |jdd}t|tjjqWdS)atrace_print(self, fmt=None) Read from the kernel debug trace pipe and print on stdout. If fmt is specified, apply as a format string to the output. See trace_fields for the members of the tuple example: trace_print(fmt="pid {1}, msg = {5}") F)rN)rrrprintrstdoutflush)r'Zfmtrrrrr trace_prints    zBPF.trace_printcCs6|dkr|dkrd}|tjkr,t|tj|<tj|S)z_sym_cache(pid) Returns a symbol cache for the specified PID. The kernel symbol cache is accessed by providing any PID less than zero. rrr5r5)r _sym_cachesr")r(rrr _sym_caches  zBPF._sym_cachec Cs6tt|}|jdd krt}t}|j|_|j|_|j|j_t j t j t j|t j|}|dkr|jr|jrd|jt j|jt jj} } } qd|d} } } q|j|jt j|jt jj} } } nt j|j||\} } } |r| dk rd| nd} | pd} | | } |r*| dk r*dtjj| nd} | | S) aysym(addr, pid, show_module=False, show_offset=False) Translate a memory address into a function name for a pid, which is returned. When show_module is True, the module name is also included. When show_offset is True, the instruction offset as a hexadecimal number is also included in the string. A pid of less than zero will access the kernel symbol cache. Example output when both show_module and show_offset are True: "start_thread+0x202 [libpthread-2.24.so]" Example output when both show_module and show_offset are False: "start_thread" Zbpf_stack_build_idrrNs+0x%xrs [unknown]s [%s]r5)rrrrrZstatusZbuild_idr,urZbcc_buildsymcache_resolver _bsymcacher#r*r+r$r-r.r/rr4rrbasename) r0r( show_module show_offsetr1Z typeofaddrr2br3r/r,r+rrrr2$s.     $zBPF.symcCstj|d||dS)aksym(addr) Translate a kernel memory address into a kernel function name, which is returned. When show_module is True, the module name ("kernel") is also included. When show_offset is true, the instruction offset as a hexadecimal number is also included in the string. Example output when both show_module and show_offset are True: "default_idle+0x0 [kernel]" rFr5)rr2)r0rrrrrksymUs zBPF.ksymcCstjdjd|S)zksymname(name) Translate a kernel name into an address. This is the reverse of ksym. Returns -1 when the function name is unknown.rNr5)rrr7)r/rrrr5csz BPF.ksymnamecCs t|jS)znum_open_kprobes() Get the number of open K[ret]probes. Can be useful for scenarios where event_re is used while attaching and detaching probes. )rr)r'rrrnum_open_kprobeskszBPF.num_open_kprobescCs t|jS)zInum_open_uprobes() Get the number of open U[ret]probes. )rr)r'rrrnum_open_uprobessszBPF.num_open_uprobescCs t|jS)zLnum_open_tracepoints() Get the number of open tracepoints. )rr)r'rrrnum_open_tracepointszszBPF.num_open_tracepointscCsLtjt|j}x"t|jjD]\}}|||<q"Wtjt|||dS)zperf_buffer_poll(self) Poll from all open perf ring buffers, calling the callback that was provided when calling open_perf_buffer for each entry. N)r#rrrrrrZperf_reader_poll)r'timeoutreadersrvrrrperf_buffer_polls zBPF.perf_buffer_pollcCsJtjt|j}x"t|jjD]\}}|||<q"Wtjt||dS)zperf_buffer_consume(self) Consume all open perf buffers, regardless of whether or not they currently contain events data. Necessary to catch 'remainder' events when wakeup_events > 1 is set in open_perf_buffer N)r#rrrrrrZperf_reader_consume)r'rrrrrrperf_buffer_consumes zBPF.perf_buffer_consumecCs|j|dS)zMkprobe_poll(self) Deprecated. Use perf_buffer_poll instead. N)r)r'rrrr kprobe_pollszBPF.kprobe_pollcCsL|js&tj||||_|jsHtdn"tj|j|||}|dkrHtddS)NzCould not open ring bufferr)rrZbpf_new_ringbufrZbpf_add_ringbuf)r'rrZctxretrrr_open_ring_buffers zBPF._open_ring_buffercCs |jstdtj|j|dS)zring_buffer_poll(self) Poll from all open ringbuf buffers, calling the callback that was provided when calling open_ring_buffer for each entry. zNo ring buffers to pollN)rrrZbpf_poll_ringbuf)r'rrrrring_buffer_pollszBPF.ring_buffer_pollcCs|jstdtj|jdS)a/ring_buffer_consume(self) Consume all open ringbuf buffers, regardless of whether or not they currently contain events data. This is best for use cases where low latency is desired, but it can impact performance. If you are unsure, use ring_buffer_poll instead. zNo ring buffers to pollN)rrrZbpf_consume_ringbuf)r'rrrring_buffer_consumeszBPF.ring_buffer_consumecCstjS)N)rZbcc_free_memory)r'rrrfree_bcc_memoryszBPF.free_bcc_memorycCsNytjtj|jWn2tk rH}ztdt|WYdd}~XnXdS)zJadd_module(modname) Add a library or exe to buildsym cache z&Error adding module to build sym cacheN)rZbcc_buildsymcache_add_modulerrrrrr)modnamer'rrr add_moduleszBPF.add_modulecCsdS)zthe do nothing exit handlerNr)r'rrrrsz BPF.donothingcCsLx.t|jjD]\}}tj|j|j|=qW|jrHtj|jd|_dS)zvclose(self) Closes all associated files descriptors. Attached BPF programs are not detached. N) rrrrrcrr+rZbpf_module_destroy)r'r/rrrrrcs    z BPF.closecCsx$t|jjD]\}}|j|qWx$t|jjD]\}}|j|q6Wx$t|jjD]\}}|j|q\Wx$t|jjD]\}}|j |qWx$t|j jD]\}}|j |qWx$t|j jD]\}}|j |qWx$t|jjD]\}}|j|qWt|jj}x(|D] }t|j|tr|j|=qWx(t|jjD]\}}|j||qRW|jr|jjd|_|j|jrtj|jd|_dS)N)rrrrIrrrrxrrdrrkrrlrrprrGrr rrrrcrrZbpf_free_ringbuf)r'krZ table_keysr rzr{rrrrs6   z BPF.cleanupcCs|S)Nr)r'rrr __enter__sz BPF.__enter__cCs |jdS)N)r)r'exc_typeZexc_valZexc_tbrrr__exit__sz BPF.__exit__r5)Nr5)F)NNN)r)rrrr)rrrr)N)N)r)r)r)rrr)rr)r)r)r)r)r)r)r)rr5r5r5r5r5)r5r5rrrr5r5r5r5r5r5r5)r5rr5r5r5r5r5)r5r5r5)rrrNrr5rr5)rrrNrr5r5)rrNr5rr5)rrNr5)F)F)F)N)FFT)FFr5)r5r5)r5)Nr5)r5)r8r9r:rWr[r\r]r^r>r_r`rarbrcrdrerfrgrhrirjrkrlrmryrzr{r|r}r~rrZXDP_FLAGS_UPDATE_IF_NOEXISTrZXDP_FLAGS_SKB_MODErZXDP_FLAGS_DRV_MODErZXDP_FLAGS_HW_MODErZXDP_FLAGS_REPLACEr"compilerrrZbcc_buildsymcache_newrrr4rr#rrZCDLLZ_librtZ clock_gettimerZc_intr%Zargtypes classmethodrrr objectr staticmethodrrr)rrrrrZc_boolZc_charZc_wcharZc_ubyteZc_shortZc_ushortZc_uintrZc_ulongZ c_longlongr6Zc_floatZc_doubleZ c_longdoubleZc_int64Zc_uint64rrr r r r rrrrrr(r*r)r0r1r2r3r7r8r9r?rFrIrHrKrLrNrOrRrSr\r]r_rbrdrerirjrkrlrnrorprqrrrvrwrxrrrrrrrrrrrrrrrrrrrrr2rr5rrrrrrrrrrrrrcrrrrrrrrsb     N    ,   B   " "       &              8   #   0       #r)@Z __future__rrZctypesr#rrrr"rrrfZlibbccrrrrrtabler r r r r ZperfrZutilsrrrrrversionrZ disassemblerrrrrrr NameErrorrr-rrrZ DEBUG_LLVM_IRrZDEBUG_PREPROCESSORZ DEBUG_SOURCErZ DEBUG_BTFrr"r;r@rDrFrWrnryrrrrrrsP    +  * __pycache__/syscall.cpython-36.opt-1.pyc000064400000021072152344707330014025 0ustar003 :)g%P@s dZddlZddlZddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;dd?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^d_d`dadbdcdddedfdgdhdidjdkdldmdndodpdqdrdsdtdudvdwdxdydzd{d|d}d~ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdROZdSdTZyNejdUdVgejdWZejdXdYdYZe e eej jdXZWn@e k rZ z"ejdZkrn e d[WYddZ [ XnXd\d]ZdS(^zRsyscall.py contains functions useful for mapping between syscall names and numbersNsreadswritesopensclosesstatsfstatslstatspollslseeksmmapsmprotectsmunmapsbrks rt_sigactionsrt_sigprocmasks rt_sigreturnsioctlspread64spwrite64sreadvswritevsaccessspipesselects sched_yieldsmremapsmsyncsmincoresmadvisesshmgetsshmatsshmctlsdupsdup2spauses nanosleeps getitimersalarms setitimersgetpidssendfilessocketsconnectsacceptssendtosrecvfromssendmsgsrecvmsgsshutdownsbindslistens getsocknames getpeernames socketpairs setsockopts getsockoptsclonesforksvforksexecvesexitswait4skillsunamessemgetssemopssemctlsshmdtsmsggetsmsgsndsmsgrcvsmsgctlsfcntlsflocksfsyncs fdatasyncstruncates ftruncatesgetdentssgetcwdschdirsfchdirsrenamesmkdirsrmdirscreatslinksunlinkssymlinksreadlinkschmodsfchmodschownsfchownslchownsumasks gettimeofdays getrlimits getrusagessysinfostimessptracesgetuidssyslogsgetgidssetuidssetgidsgeteuidsgetegidssetpgidsgetppidsgetpgrpssetsidssetreuidssetregids getgroupss setgroupss setresuids getresuids setresgids getresgidsgetpgidssetfsuidssetfsgidsgetsidscapgetscapsets rt_sigpendingsrt_sigtimedwaitsrt_sigqueueinfos rt_sigsuspends sigaltstacksutimesmknodsuselibs personalitysustatsstatfssfstatfsssysfss getprioritys setpriorityssched_setparamssched_getparamssched_setschedulerssched_getschedulerssched_get_priority_maxssched_get_priority_minssched_rr_get_intervalsmlocksmunlocksmlockalls munlockallsvhangups modify_ldts pivot_roots_sysctlsprctls arch_prctlsadjtimexs setrlimitschrootssyncsaccts settimeofdaysmountsumount2sswaponsswapoffsreboots sethostnames setdomainnamesioplsioperms create_modules init_modules delete_modulesget_kernel_symss query_modulesquotactls nfsservctlsgetpmsgsputpmsgs afs_syscallstuxcallssecuritysgettids readaheadssetxattrs lsetxattrs fsetxattrsgetxattrs lgetxattrs fgetxattrs listxattrs llistxattrs flistxattrs removexattrs lremovexattrs fremovexattrstkillstimesfutexssched_setaffinityssched_getaffinitysset_thread_areasio_setups io_destroys io_geteventss io_submits io_cancelsget_thread_areaslookup_dcookies epoll_creates epoll_ctl_oldsepoll_wait_oldsremap_file_pagess getdents64sset_tid_addresssrestart_syscalls semtimedops fadvise64s timer_creates timer_settimes timer_gettimestimer_getoverruns timer_deletes clock_settimes clock_gettimes clock_getressclock_nanosleeps exit_groups epoll_waits epoll_ctlstgkillsutimessvserversmbinds set_mempolicys get_mempolicysmq_opens mq_unlinks mq_timedsendsmq_timedreceives mq_notifys mq_getsetattrs kexec_loadswaitidsadd_keys request_keyskeyctls ioprio_sets ioprio_gets inotify_initsinotify_add_watchsinotify_rm_watchs migrate_pagessopenatsmkdiratsmknodatsfchownats futimesats newfstatatsunlinkatsrenameatslinkats symlinkats readlinkatsfchmodats faccessatspselect6sppollsunsharesset_robust_listsget_robust_listssplicesteessync_file_rangesvmsplices move_pagess utimensats epoll_pwaitssignalfdstimerfd_createseventfds fallocatestimerfd_settimestimerfd_gettimesaccept4s signalfd4seventfd2s epoll_create1sdup3spipe2s inotify_init1spreadvspwritevsrt_tgsigqueueinfosperf_event_opensrecvmmsgs fanotify_inits fanotify_marks prlimit64sname_to_handle_atsopen_by_handle_ats clock_adjtimessyncfsssendmmsgssetnssgetcpusprocess_vm_readvsprocess_vm_writevskcmps finit_modules sched_setattrs sched_getattrs renameat2sseccomps getrandoms memfd_createskexec_file_loadsbpfsexecveats userfaultfds membarriersmlock2scopy_file_rangespreadv2spwritev2s pkey_mprotects pkey_allocs pkey_freesstatxs io_pgeteventssrseq(Or  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~iiiiiiiii i i i i iiiiiiiiiiiiiiiiiii i!i"i#i$i%i&i'i(i)i*i+i,i-i.i/i0i1i2i3i4i5i6i7i8i9i:i;i<i=i>i?i@iAiBiCiDiEiFiGiHiIiJiKiLiMiNcCs |j}t|d|djfS)Nrr)splitintstrip)linepartsr/usr/lib/python3.6/syscall.py_parse_syscalltsr Z ausyscallz--dump)stderr rZx86_64zausyscall: command not foundcCstj|d|S)z:Return the syscall name for the particular syscall number.s [unknown: %d])syscallsget)Z syscall_numrrr syscall_namesr)__doc__ subprocessplatformr r Z check_outputZSTDOUToutrdictmapr Exceptionemachinerrrrrs  __pycache__/containers.cpython-36.pyc000064400000006242152344707330013563 0ustar003 :)gk@sddZddZddZdS)cCs|sdSd}|jd|S)NzV static inline int _cgroup_filter() { return 0; } z BPF_TABLE_PINNED("hash", u64, u64, cgroupset, 1024, "CGROUP_PATH"); static inline int _cgroup_filter() { u64 cgroupid = bpf_get_current_cgroup_id(); return cgroupset.lookup(&cgroupid) == NULL; } Z CGROUP_PATH)replace) cgroupmaptextr /usr/lib/python3.6/containers.py_cgroup_filter_func_writers rcCs|sdSd}|jd|S)NzU static inline int _mntns_filter() { return 0; } a #include #include #include /* see mountsnoop.py: * XXX: struct mnt_namespace is defined in fs/mount.h, which is private * to the VFS and not installed in any kernel-devel packages. So, let's * duplicate the important part of the definition. There are actually * more members in the real struct, but we don't need them, and they're * more likely to change. */ struct mnt_namespace { // This field was removed in https://github.com/torvalds/linux/commit/1a7b8969e664d6af328f00fe6eb7aabd61a71d13 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0) atomic_t count; #endif struct ns_common ns; }; /* * To add mountsnoop support for --selector option, we need to call * filter_by_containers(). * This function adds code which defines struct mnt_namespace. * The problem is that this struct is also defined in mountsnoop BPF code. * To avoid redefining it in mountnsoop code, we define * MNT_NAMESPACE_DEFINED here. * Then, in mountsnoop code, the struct mnt_namespace definition is guarded * by: * #ifndef MNT_NAMESPACE_DEFINED * // ... * #endif */ #define MNT_NAMESPACE_DEFINED BPF_TABLE_PINNED("hash", u64, u32, mount_ns_set, 1024, "MOUNT_NS_PATH"); static inline int _mntns_filter() { struct task_struct *current_task; struct nsproxy *nsproxy; struct mnt_namespace *mnt_ns; unsigned int inum; u64 ns_id; current_task = (struct task_struct *)bpf_get_current_task(); if (bpf_probe_read_kernel(&nsproxy, sizeof(nsproxy), ¤t_task->nsproxy)) return 0; if (bpf_probe_read_kernel(&mnt_ns, sizeof(mnt_ns), &nsproxy->mnt_ns)) return 0; if (bpf_probe_read_kernel(&inum, sizeof(inum), &mnt_ns->ns.inum)) return 0; ns_id = (u64) inum; return mount_ns_set.lookup(&ns_id) == NULL; } Z MOUNT_NS_PATH)r)mntnsmaprrrr_mntns_filter_func_writer"s;rcCs$d}t|j}t|j}|||S)Nzv static inline int container_should_be_filtered() { return _cgroup_filter() || _mntns_filter(); } )rrrr)argsZfilter_by_containers_textZcgroupmap_textZ mntnsmap_textrrrfilter_by_containersgs  r N)rrr rrrrsE__pycache__/perf.cpython-36.pyc000064400000012275152344707330012355 0ustar003 :)g @sxddlZddlZddlmZGdddejZGdddejZGdd d ejZGd d d ejZ Gd d d e Z dS)N)get_online_cpusc@s eZdZdejfdejfgZdS)_sample_period_union sample_periodZ sample_freqN)__name__ __module__ __qualname__ctc_ulong_fields_r r /usr/lib/python3.6/perf.pyrsrc@s eZdZdejfdejfgZdS)_wakeup_events_union wakeup_eventsZwakeup_watermarkN)rrrr c_uintr r r r r rsrc@s0eZdZdejfdejfdejfdejfgZdS)_bp_addr_unionZbp_addrZ kprobe_funcZ uprobe_pathZconfig1N)rrrr r r r r r r rsrc@s0eZdZdejfdejfdejfdejfgZdS) _bp_len_unionZbp_lenZ kprobe_addrZ probe_offsetZconfig2N)rrrr r r r r r r r'src@s|eZdZGdddejZdZdZdZdZ dZ dZ d Z d Z d Zejd d dZejZejZeddZede dfddZdS)Perfc7s eZdZddddgZdejfdejfdejfdefdejfd ejfd ejd fd ejd fd ejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejdfdejd fdejd fdejd fdejd fd ejd fd!ejd fd"ejd fd#ejd fd$ejd fd%ejd fd&ejd fd'ejd fd(ejd fd)ejd fd*ejd fd+ejd fd,ejd fd-ejd.fdefd/ejfde fde fd0ejfd1ejfd2ejfd3ej fd4ejfd5ejfd6ej fd7ej fd8ejfd9ejfg6Z d:d;ZfdzPerf.perf_event_attrrrrrtypesizeconfig sample_typeZ read_formatZdisabledrZinheritZpinnedZ exclusiveZ exclude_userZexclude_kernelZ exclude_hvZ exclude_idleZmmapZcommfreqZ inherit_statZenable_on_execZtaskZ watermarkZ precise_ipZ mmap_dataZ sample_id_allZ exclude_hostZ exclude_guestZexclude_callchain_kernelZexclude_callchain_userZmmap2Z comm_execZ use_clockidZcontext_switchZwrite_backwardZ namespacesZksymbolZ bpf_eventZ aux_outputZcgroupZ text_pokeZ __reserved_1Zbp_typeZbranch_sample_typeZsample_regs_userZsample_stack_userZclockidZsample_regs_intrZ aux_watermarkZsample_max_stackZ __reserved_2Zaux_sample_sizeZ __reserved_3cCs|d|_dd|jD|_|jjddtjD|jjddtjD|jjddtjD|jjddtjDdS)NxcSsg|] }|dqS)rr ).0itemr r r tsz1Perf.perf_event_attr.__init__..cSsg|] }|dqS)rr )rrr r r ruscSsg|] }|dqS)rr )rrr r r rvscSsg|] }|dqS)rr )rrr r r rwscSsg|] }|dqS)rr )rrr r r rxs)rr ctype_fieldsextendrrrr)selfr r r __init__rs zPerf.perf_event_attr.__init__cs<t|dr$||jkr$tdj||ttj|j||dS)NrzoWarning: Setting field {} on perf_event_attr that isn't part of the ctype - {} won't make it to perf_event_open)hasattrrprintformatsuperrperf_event_attr __setattr__)r!keyvalue) __class__r r r(zsz Perf.perf_event_attr.__setattr__)rrrZ _anonymous_r rr rrrrZc_intZc_uint16r r"r( __classcell__r r )r+r r'1sx                                   r'i*rrrii$@i$z libc.so.6T)Z use_errnocCstjtjtj||j|dtj}|dkr@tj}t|t j ||j tj krxtj |tjddkrxtj}t|t j |tj |tjddkrtj}t|t j |dS)Nrrzcommon_pid == -17)rsyscallNR_PERF_EVENT_OPENr ZbyrefpidPERF_FLAG_FD_CLOEXECZ get_errnoOSErrorosstrerrorrPERF_TYPE_TRACEPOINTioctlPERF_EVENT_IOC_SET_FILTERPERF_EVENT_IOC_ENABLE)cpuattrZpfdZerrno_r r r _open_for_cpus   zPerf._open_for_cpucCsdtj}||_||_||_tj|_|dkr8d|_||_nd|_d|_ xt D]}tj ||qLWdS)Nrri) rr'rr2rPERF_SAMPLE_RAWrrrrrr=)Z tpoint_idr2Zptyperr<r;r r r perf_event_opens zPerf.perf_event_openNr/)rrrr Z Structurer'r1ZPERF_TYPE_HARDWAREZPERF_TYPE_SOFTWAREr7ZPERF_TYPE_HW_CACHEr>r3r9r:ZCDLLZlibcr0r8 staticmethodr=r?r r r r r/s"O r) Zctypesr r5ZutilsrZUnionrrrrobjectrr r r r s __pycache__/version.cpython-36.opt-1.pyc000064400000000206152344707330014034 0ustar003 :)g@sdZdS)z0.25.0N) __version__rr/usr/lib/python3.6/version.pys__pycache__/disassembler.cpython-36.pyc000064400000030363152344707330014074 0ustar003 :)gP@sddlmZddlZddlmZGdddejZGdddejZGd d d ej Z Gd d d ejZ Gd ddZ dddZ ddZddZGdddZdddZdS))linesepN)get_table_type_namec@s eZdZdejfdejfgZdS) OffsetUnionZoffsetuoffsetN)__name__ __module__ __qualname__ctZc_uint16Zc_int16_fields_r r "/usr/lib/python3.6/disassembler.pyrsrc@s eZdZdejfdejfgZdS)ImmUnionimmuimmN)rrr r Zc_uint32Zc_int32r r r r r rsrc@s@eZdZdZd ZdejfdejdfdejdfdefdefgZ dS) BPFInstrFieldsroiopcodedstsrcN)rr) rrr _pack_ _anonymous_r Zc_uint8rrr r r r r rs  rc@s&eZdZdZdZdefdejfgZdS)BPFInstrrsinstrN) rrr rrrr c_uint64r r r r r r"srcd@seZdZdZdddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;dd?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUdVdWdXdYdZd[d\d]d^g]Zdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd d d d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*dǜaZeddɄZdeS(+ BPFDecoderrZunspecZmap_lookup_elemZmap_update_elemZmap_delete_elemZ probe_readZ ktime_get_nsZ trace_printkZget_prandom_u32Zget_smp_processor_idZskb_store_bytesZl3_csum_replaceZl4_csum_replaceZ tail_callZclone_redirectZget_current_pid_tgidZget_current_uid_gidZget_current_commZget_cgroup_classidZ skb_vlan_pushZ skb_vlan_popZskb_get_tunnel_keyZskb_set_tunnel_keyZperf_event_readZredirectZget_route_realmZperf_event_outputZskb_load_bytesZ get_stackidZ csum_diffZskb_get_tunnel_optZskb_set_tunnel_optZskb_change_protoZskb_change_typeZskb_under_cgroupZget_hash_recalcZget_current_taskZprobe_write_userZcurrent_task_under_cgroupZskb_change_tailZ skb_pull_dataZ csum_updateZset_hash_invalidZget_numa_node_idZskb_change_headZxdp_adjust_headZprobe_read_strZget_socket_cookieZget_socket_uidZset_hashZ setsockoptZskb_adjust_roomZ redirect_mapZsk_redirect_mapZsock_map_updateZxdp_adjust_metaZperf_event_read_valueZperf_prog_read_valueZ getsockoptZoverride_returnZsock_ops_cb_flags_setZmsg_redirect_mapZmsg_apply_bytesZmsg_cork_bytesZ msg_pull_dataZbindZxdp_adjust_tailZskb_get_xfrm_stateZ get_stackZskb_load_bytes_relativeZ fib_lookupZsock_hash_updateZmsg_redirect_hashZsk_redirect_hashZlwt_push_encapZlwt_seg6_store_bytesZlwt_seg6_adjust_srhZlwt_seg6_actionZ rc_repeatZ rc_keydownZ skb_cgroup_idZget_current_cgroup_idZget_local_storageZsk_select_reuseportZskb_ancestor_cgroup_idZ sk_lookup_tcpZ sk_lookup_udpZ sk_releaseZ map_push_elemZ map_pop_elemZ map_peek_elemZ msg_push_dataZ msg_pop_dataZrc_pointer_reladd32dstimm+= jajoffN@adddstsrcsub32-=jeq jdstimmoff==sublddw jdstsrcoffldabswldabsmul32*=jgt>mulldabshldabsbdiv32/=jge>=divldabsdwldindwldindor32 dstimm_bw|=jset&orldindhldindband32&=jne!=andldinddwldxw ldstsrcoffstw sdstoffimmstxw sdstoffsrclsh32<<=jsgts>lshldxhsthstxhldxbstbstxbrsh32>>=jsges>=rshldxdwstdwstxdwneg32r~callnegmod32%=exitmodxor32^=jlt<xormov32=jle<=movarsh32s>>=jslts<arshjsles<=endian32endian)ar r"$%'(,-/04578<=?r%DEGHLMOPTUWX\]_abcdegijklmoqrstuwyz{|}c Csy|j|j\}}}}|dkr6d|j||jfdfS|dkrTd|j||jfdfS|dkr|dd|j||jd fdfS|d krd |j||jfdfS|d krd |j||jd|j||jd fdfS|dkrd|j||jd|j||jd fdfS|dkr^|dkrtd|jdkr|jB}d|j|fd fS|dkrzd||jfdfS|dkrd||jd|jfdfS|dkrd|j||jd|jfdfS|dkrd||jd|j|jfdfS|dkrd||jd|j|jfdfS|dkr8d |j|||jfdfS|d!kr|j|jkryd"||j |j|jfdfSt k rd#||jfdfSXd$|d|jfdfS|d%kr|dfStd&Wnt k rd'|jSXdS)(Nr z r%d %s %drrDz r%d %s 0x%xr$z goto %s <%d>z%+drr'z r%d %s r%dr+zif r%d %s %d goto pc%s <%d>r/zif r%d %s r%d goto pc%s <%d>r.z1lddw requires two instructions to be disassembledzr%d = r"z r%d = 0x%xr1zr0 = *(u%s*)skb[%s]rBzr0 = *(u%d*)skb[r%d %s]rRzr%d = *(u%d*)(r%d %s)rTz*(u%d*)(r%d %s) = %drVz*(u%d*)(r%d %s) = r%drzr%d = %s (u%s)r%drlz %s bpf_%s#%dz%s z%s %srpzunknown opcode classzunknown <0x%x>) opcodesrrrrrr ExceptionBPF_PSEUDO_CALL bpf_helpers IndexErrorKeyError) clsrww1nameZopclassopbitsrr r r decodesl                 zBPFDecoder.decode)rr r!r")r#r$Nr%)r&r r!r%)rr'r!r")r&r'r!r%)r(r r)r")r*r+r,r%)r-r r)r%)r.r.Nr%)r(r'r)r")r*r/r,r%)r-r'r)r%)r0r1Nr")r2r r3r")r4r+r5r%)r6r r3r%)r7r1Nr8)r2r'r3r")r4r/r5r%)r6r'r3r%)r9r1Nr:)r;r r<r")r=r+r>r%)r?r r<r%)r@r1Nr%)r;r'r<r")r=r/r>r%)r?r'r<r%)rArBNr")rCrDrEr")rFr+rGr%)rHrDrEr%)rIrBNr8)rCr'rEr")rFr/rGr%)rHr'rEr%)rJrBNr:)rKrDrLr")rMr+rNr%)rOrDrLr%)rPrBNr%)rKr'rLr")rMr/rNr%)rOr'rLr%)rQrRNr")rSrTNr")rUrVNr")rWr rXr")rYr+rZr%)r[r rXr%)r\rRNr8)r]rTNr8)r^rVNr8)rWr'rXr")rYr/rZr%)r[r'rXr%)r_rRNr:)r`rTNr:)rarVNr:)rbr rcr")rdr+rer%)rfr rcr%)rgrRNr%)rhrTNr%)rirVNr%)rbr'rcr")rdr/rer%)rfr'rcr%)rjrrkr")rlrlNr%)rmrrkr%)rnr ror")rprpNr%)rqr ror%)rnr'ror")rqr'ror%)rrrDrsr")rtr+rur%)rvrDrsr%)rrr'rsr")rtr/rur%)rvr'rsr%)rwr rxr")ryr+rzr%)r{r rxr%)rwr'rxr")ryr/rzr%)r{r'rxr%)r|r r}r")r~r+rr%)rr r}r%)r|r'r}r")r~r/rr%)rr'r}r%)rr+rr%)rr'rr")rr+rr%)rrr rrr classmethodrr r r r r's rcCs&tj|||\}}d||j|f|fS)Nz%4d: (%02x) %s)rrr)rw0rrskipr r r disassemble_instruction3src Cstjtj|tjt}tt|d}|d}d}g}xRtd|D]D}||}|rf|d8}d|}nt|d||\}}|j ||}qDWt|d|d\}}|j ||S)Nr:rrz%4d: (64-bit upper word)) r castZc_char_pZPOINTERrintlenrangerappend) bpfstrZptrZnuminstrrr instr_listrrZ instr_strr r r disassemble_str7s    rcCs d|g}|t|7}tj|S)NzDisassemble of BPF program %s:)rrjoin)Z func_namerrr r r disassemble_progJs  rc"@seZdZejdejdejdejdejdej dej dej dej d ej d ejd ejd ejd ejdejdejddejddiZeddZed!ddZed"ddZeddZed#dd ZdS)$ MapDecoderZ_BoolcharZwchar_tz unsigned charZshortzunsigned shortrz unsigned intZlongz unsigned longz long longzunsigned long longfloatZdoublez long doubleZ__int128zunsigned __int128c Csy^t|tjrd}nHt|tjr&d}n6t|tjrR|j|jdt|jd}n |j|}Wnt k rzt|}YnX|S)Nstructunion[]) issubclassr StructureUnionZArray ctype2strZ_type_strZ_length_r)rtfield_type_namer r r get_ct_namebs    zMapDecoder.get_ct_nameFNcCs*|sdS|dk rd|||fSd||fS)Nz[%d,%d +%d bit]z [%d +%d] r )rrsizeZenabledZ bitoffsetr r r format_size_infoqs zMapDecoder.format_size_inforrcCsg}yx|jD]\}}t|tjp,t|tj}|j|} t||j} tj|} |j || | |} |r|j d|| | f||j ||d|| 7}|j d||fq|j d|| | |fqWWnt k rd} x|jD]}t |dkr0|\}}}|j|} |j || ||} |j d|| | ||fn`|\}}|j|} t||j} tj|} d}d} |j || | |} |j d|| | |f|| 7}| |7} qWYnX|S)Nz%s%s%s {z z%s} %s;z %s%s%s %s;rz %s%s%s %s:%d;)r rr rrr getattrrZsizeofrr print_ct_map ValueErrorr)rr indentrsizeinfo map_lines field_nameZ field_type is_structuredr Z field_offsetZ field_sizeZsizedescZ offset_bitsZfieldZ field_bitsr r r rysZ                   zMapDecoder.print_ct_mapcCsft|tjpt|tj}|j|}|rTd|g}||j|d|d7}|jd|nd||fg}|S)Nz %s {z )rz } %s;z %s %s;)rr rrr rr)rr rrrZ type_namerr r r print_map_ctypes    zMapDecoder.print_map_ctypecCsLd|||j|jfg}||j|jd|d7}||j|jd|d7}tj|S)Nz-Layout of BPF map %s (type %s, FD %d, ID %d):key)rvalue)Zmap_fdZmap_idrZKeyZLeafrr)rmap_namemap_objmap_typerrr r r decode_maps zMapDecoder.decode_map)FN)rrF)F)rrr r Zc_boolZc_charZc_wcharZc_ubyteZc_shortZc_ushortZc_intZc_uintZc_longZc_ulongZ c_longlongZ c_ulonglongZc_floatZc_doubleZ c_longdoubleZc_int64rr rr rrrr r r r r rOs2    3 rFcCst|}tj||||dS)N)r)rrr )rrrrZ map_type_namer r r r sr )N)F)osrZctypesr tablerrrrrrrrrrrrr r r r r s    u__pycache__/perf.cpython-36.opt-1.pyc000064400000012275152344707330013314 0ustar003 :)g @sxddlZddlZddlmZGdddejZGdddejZGdd d ejZGd d d ejZ Gd d d e Z dS)N)get_online_cpusc@s eZdZdejfdejfgZdS)_sample_period_union sample_periodZ sample_freqN)__name__ __module__ __qualname__ctc_ulong_fields_r r /usr/lib/python3.6/perf.pyrsrc@s eZdZdejfdejfgZdS)_wakeup_events_union wakeup_eventsZwakeup_watermarkN)rrrr c_uintr r r r r rsrc@s0eZdZdejfdejfdejfdejfgZdS)_bp_addr_unionZbp_addrZ kprobe_funcZ uprobe_pathZconfig1N)rrrr r r r r r r rsrc@s0eZdZdejfdejfdejfdejfgZdS) _bp_len_unionZbp_lenZ kprobe_addrZ probe_offsetZconfig2N)rrrr r r r r r r r'src@s|eZdZGdddejZdZdZdZdZ dZ dZ d Z d Z d Zejd d dZejZejZeddZede dfddZdS)Perfc7s eZdZddddgZdejfdejfdejfdefdejfd ejfd ejd fd ejd fd ejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejd fdejdfdejd fdejd fdejd fdejd fd ejd fd!ejd fd"ejd fd#ejd fd$ejd fd%ejd fd&ejd fd'ejd fd(ejd fd)ejd fd*ejd fd+ejd fd,ejd fd-ejd.fdefd/ejfde fde fd0ejfd1ejfd2ejfd3ej fd4ejfd5ejfd6ej fd7ej fd8ejfd9ejfg6Z d:d;ZfdzPerf.perf_event_attrrrrrtypesizeconfig sample_typeZ read_formatZdisabledrZinheritZpinnedZ exclusiveZ exclude_userZexclude_kernelZ exclude_hvZ exclude_idleZmmapZcommfreqZ inherit_statZenable_on_execZtaskZ watermarkZ precise_ipZ mmap_dataZ sample_id_allZ exclude_hostZ exclude_guestZexclude_callchain_kernelZexclude_callchain_userZmmap2Z comm_execZ use_clockidZcontext_switchZwrite_backwardZ namespacesZksymbolZ bpf_eventZ aux_outputZcgroupZ text_pokeZ __reserved_1Zbp_typeZbranch_sample_typeZsample_regs_userZsample_stack_userZclockidZsample_regs_intrZ aux_watermarkZsample_max_stackZ __reserved_2Zaux_sample_sizeZ __reserved_3cCs|d|_dd|jD|_|jjddtjD|jjddtjD|jjddtjD|jjddtjDdS)NxcSsg|] }|dqS)rr ).0itemr r r tsz1Perf.perf_event_attr.__init__..cSsg|] }|dqS)rr )rrr r r ruscSsg|] }|dqS)rr )rrr r r rvscSsg|] }|dqS)rr )rrr r r rwscSsg|] }|dqS)rr )rrr r r rxs)rr ctype_fieldsextendrrrr)selfr r r __init__rs zPerf.perf_event_attr.__init__cs<t|dr$||jkr$tdj||ttj|j||dS)NrzoWarning: Setting field {} on perf_event_attr that isn't part of the ctype - {} won't make it to perf_event_open)hasattrrprintformatsuperrperf_event_attr __setattr__)r!keyvalue) __class__r r r(zsz Perf.perf_event_attr.__setattr__)rrrZ _anonymous_r rr rrrrZc_intZc_uint16r r"r( __classcell__r r )r+r r'1sx                                   r'i*rrrii$@i$z libc.so.6T)Z use_errnocCstjtjtj||j|dtj}|dkr@tj}t|t j ||j tj krxtj |tjddkrxtj}t|t j |tj |tjddkrtj}t|t j |dS)Nrrzcommon_pid == -17)rsyscallNR_PERF_EVENT_OPENr ZbyrefpidPERF_FLAG_FD_CLOEXECZ get_errnoOSErrorosstrerrorrPERF_TYPE_TRACEPOINTioctlPERF_EVENT_IOC_SET_FILTERPERF_EVENT_IOC_ENABLE)cpuattrZpfdZerrno_r r r _open_for_cpus   zPerf._open_for_cpucCsdtj}||_||_||_tj|_|dkr8d|_||_nd|_d|_ xt D]}tj ||qLWdS)Nrri) rr'rr2rPERF_SAMPLE_RAWrrrrrr=)Z tpoint_idr2Zptyperr<r;r r r perf_event_opens zPerf.perf_event_openNr/)rrrr Z Structurer'r1ZPERF_TYPE_HARDWAREZPERF_TYPE_SOFTWAREr7ZPERF_TYPE_HW_CACHEr>r3r9r:ZCDLLZlibcr0r8 staticmethodr=r?r r r r r/s"O r) Zctypesr r5ZutilsrZUnionrrrrobjectrr r r r s __pycache__/tcp.cpython-36.pyc000064400000001724152344707330012204 0ustar003 :)g2@siZded<ded<ded<ded<ded <d ed <d ed <ded<ded<ded<ded<ded<dZdZdZdZdZdZdZdZddZ dS)Z ESTABLISHEDZSYN_SENTZSYN_RECVZ FIN_WAIT1Z FIN_WAIT2Z TIME_WAITZCLOSEZ CLOSE_WAITZLAST_ACK ZLISTEN ZCLOSING Z NEW_SYN_RECV  @cCsg}|t@r|jd|t@r(|jd|t@r:|jd|t@rL|jd|t@r^|jd|t@rp|jd|t@r|jd|t@r|jdd j |S) NZFINZSYNZRSTZPSHZACKZURGZECEZCWR|) TCPHDR_FINappend TCPHDR_SYN TCPHDR_RST TCPHDR_PSH TCPHDR_ACK TCPHDR_URG TCPHDR_ECE TCPHDR_CWRjoin)flagsZarrr/usr/lib/python3.6/tcp.py flags2str(s$        rN) Ztcpstaterrrrrrrrrrrrrs*__pycache__/table.cpython-36.opt-1.pyc000064400000131750152344707330013447 0ustar003 :)gB@s4ddlmZyddlmZWn ek r<ddlmZYnXddlmZddlZ ddl m Z ddl Z ddl Z ddlZddlZddlmZmZmZmZmZddlmZdd lmZdZd Zd Zd Zd ZdZdZdZ dZ!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.dZ/d Z0d!Z1d"Z2d#Z3d$Z4d%Z5ed&ed'ed(ed)ed*ed+ed,e d-e!d.e"d/e#d0e$d1e%d2e&d3e'd4e(d5e)d6e*d7e+d8e,d9e-d:e.d;e/de2d?e3d@e4dAe5dBiZ6dCa7dDZ8dEZ9dFdGZ:d~dHdIZ;dJdKZdPdQZ?dRdSZ@GdTdUdUeZAGdVdWdWeAZBGdXdYdYeBZCGdZd[d[eAZDGd\d]d]eDZEGd^d_d_eDZFGd`dadaZGGdbdcdceDZHGdddedeeDZIGdfdgdgeBZJGdhdidieJZKGdjdkdkeDZLGdldmdmeAZMGdndodoeAZNGdpdqdqeDZOGdrdsdseDZPGdtdudueDZQGdvdwdweDZRGdxdydyeBZSGdzd{d{eAZTGd|d}d}ZUdS))print_function)MutableMapping)strftimeN)reduce)lib _RAW_CB_TYPE _LOST_CB_TYPE_RINGBUF_CB_TYPEbcc_perf_buffer_opts)get_online_cpus)get_possible_cpus ZHASHZARRAYZ PROG_ARRAYZPERF_EVENT_ARRAYZ PERCPU_HASHZ PERCPU_ARRAYZ STACK_TRACEZ CGROUP_ARRAYZLRU_HASHZLRU_PERCPU_HASHZLPM_TRIEZ ARRAY_OF_MAPSZ HASH_OF_MAPSZDEVMAPZSOCKMAPZCPUMAPZXSKMAPZSOCKHASHZCGROUP_STORAGEZREUSEPORT_SOCKARRAYZPERCPU_CGROUP_STORAGEZQUEUEZSTACKZ SK_STORAGEZ DEVMAP_HASHZ STRUCT_OPSZRINGBUFZ INODE_STORAGEZ TASK_STORAGE(AicCs\d}d}x6||||dks*||dkr,P|d7}|d7}q W||krX|ddd}|S)Nrr*+)valval_maxwidthitextr0r0/usr/lib/python3.6/table.py_starscs  r7c Csg}d}x$tt|D]}||dkr|}qWd}d}xftt|D]V}|dkrD||krD|d}i}||d<t|d|d<t|||d<|j||}qDWtd||d} |r|d| |d<t| dS) Nrrrzinterval-startz interval-endcountz%Y-%m-%d %H:%M:%S)Ztsval_typedata)rangelenintappendrprint) valsr9section_bucketZ hist_listZmax_nonzero_idxr4indexprevZlist_objZ histogramr0r0r6_print_json_histos(  rDc Csd}d }d}x,t|D] \}}|dkr*|}||kr|}qW|dkrPd}d} t} nd}d} ttd } |dkrxt||xtd|dD]~}d|>d?} d|>d} | | kr| d8} ||} |r| rt| | | | | t| || fd }qt| | | | | t| || fqWdS) N@rr z# %-19s : count distributionz%10d -> %-10d : %-8d |%-*s|z- %-29s : count distributionz%20d -> %-20d : %-8d |%-*s|rFr/) enumerate stars_maxr=r?r;r7)r@r9strip_leading_zero log2_dist_maxidx_maxr2r4vheaderbodystarsZlowZhighr1r0r0r6_print_log2_hists<      rPc Csd}d}d}x,t|D] \}}|dkr*|}||kr|}qWd}d} t} |dkrZt||xdtd|dD]R}||} |r| rt| || | t| || fd}qjt| || | t| || fqjWdS)NrErrz# %-13s : count distributionz %-10d : %-8d |%-*s|Fr/)rGrHr?r;r7) r@r9rIrJrKr2r4rLrMrNrOr1r0r0r6_print_linear_hists,   rQc Cs"yt|Stk rdSXdS)Nz ) map_type_nameKeyError)ttyper0r0r6get_table_type_namesrUc Cstjtjtjtjtjtjtjtjtjtjtjtjtjtjtjtjtj tj tj tj tj tj dtj dtj d}t jd}g}tj|jj|j}d}x||krrtj|jj|j|j}t jd|}|jd}|jd} t jd| rd} |j| }yD|r |j|||jdt|jdfn|j||| fWn2tk rftd | tjd tjdYnX|d7}qWtd tj fd |iS) Nr)charZs8z unsigned charu8zu8 *zchar *ZshortZs16zunsigned shortu16r=Zs32enumz unsigned intu32Zlongz unsigned longz long longZs64zunsigned long longZu64Z__int128zunsigned __int128zvoid *z([^ ]+) ?\[([0-9]+)\]$rz (.*)#(.*)rzenum .*rYzGType: '%s' not recognized. Please define the data with ctypes manually.)filer,_fields_)!ctZc_charZc_ubyteZc_char_pZc_shortZc_ushortc_intc_uintZc_longZc_ulongZ c_longlongZ c_ulonglongZc_void_precompilerZbpf_perf_event_fieldsbpfmodule_nameZbpf_perf_event_fielddecodematchgroupr>r=rSr?sysstderrexittype Structure) Z event_mapZ ct_mappingZ array_typeZfields num_fieldsr4ZfieldmZ field_nameZ field_typer0r0r6_get_event_classs\        ( roc Ks8tj|j|}d}|tkr.t|||||}n|tkrJt|||||}n|tkrft|||||}n|t krt ||||||}n|t krt |||||f|}nz|t krt|||||f|}nZ|tkrt|||||}n>|tkrt|||||}n"|tkrt|||||}n|tkr6t|||||}n|tkrRt|||||}n|tkrnt|||||}n|tkrt|||||}n|tkrt|||||}nx|tkrt |||||}n\|t!krt"|||||}n@|t#ks|t$krt%||||}n|t&krt'||||||}|dkr4t(d||S)z|Table(bpf, map_id, map_fd, keytype, leaftype, **kwargs) Create a python object out of a reference to a bpf table handleNzUnknown table type %d))rbpf_table_type_idrcBPF_MAP_TYPE_HASH HashTableBPF_MAP_TYPE_ARRAYArrayBPF_MAP_TYPE_PROG_ARRAY ProgArrayBPF_MAP_TYPE_PERF_EVENT_ARRAYPerfEventArrayBPF_MAP_TYPE_PERCPU_HASH PerCpuHashBPF_MAP_TYPE_PERCPU_ARRAY PerCpuArrayBPF_MAP_TYPE_LPM_TRIELpmTrieBPF_MAP_TYPE_STACK_TRACE StackTraceBPF_MAP_TYPE_LRU_HASHLruHashBPF_MAP_TYPE_LRU_PERCPU_HASH LruPerCpuHashBPF_MAP_TYPE_CGROUP_ARRAY CgroupArrayBPF_MAP_TYPE_DEVMAPDevMapBPF_MAP_TYPE_CPUMAPCpuMapBPF_MAP_TYPE_XSKMAPXskMapBPF_MAP_TYPE_ARRAY_OF_MAPS MapInMapArrayBPF_MAP_TYPE_HASH_OF_MAPS MapInMapHashBPF_MAP_TYPE_QUEUEBPF_MAP_TYPE_STACK QueueStackBPF_MAP_TYPE_RINGBUFRingBuf Exception) rbmap_idmap_fdkeytypeleaftypenamekwargsrTtr0r0r6Table sR           rc@seZdZdDddZddZddZdd Zd d Zd d ZddZ ddZ ddZ ddZ ddZ ddZddZddZdEdd ZdFd!d"Zd#d$ZdGd%d&Zd'd(Zd)d*ZdHd,d-Zd.d/Zd0d1Zd2d3Zd4d5ZGd6d7d7eZd8d9Zd:d;ZdId>d?Z dJd@dAZ!dKdBdCZ"dS)L TableBaseNcCsn||_||_||_||_||_tj|jj|j|_tj |jj|j|_ i|_ ||_ t tj|jj|j|_dS)N)rbrrKeyLeafrrprcrTbpf_table_flags_idflags_cbsrdr=bpf_table_max_entries_id max_entries)selfrbrrrrrr0r0r6__init__?s zTableBase.__init__cCs|jS)N)r)rr0r0r6get_fdLszTableBase.get_fdcCsNtjtj|jd}tj|jj|j|t |tj |}|dkrHt d|j S)NrrzCould not printf key) r]create_string_buffersizeofrrZbpf_table_key_snprintfrbrcrr<byrefrvalue)rkeybufresr0r0r6 key_sprintfOs zTableBase.key_sprintfcCsNtjtj|jd}tj|jj|j|t |tj |}|dkrHt d|j S)NrrzCould not printf leaf) r]rrrrbpf_table_leaf_snprintfrbrcrr<rrr)rleafrrr0r0r6 leaf_sprintfWs zTableBase.leaf_sprintfcCs8|j}tj|jj|j|tj|}|dkr4td|S)NrzCould not scanf key) rrZbpf_table_key_sscanfrbrcrr]rr)rZkey_strrrr0r0r6 key_scanf_s  zTableBase.key_scanfcCs8|j}tj|jj|j|tj|}|dkr4td|S)NrzCould not scanf leaf) rrbpf_table_leaf_sscanfrbrcrr]rr)rleaf_strrrr0r0r6 leaf_scanfgs  zTableBase.leaf_scanfcCs4|j}tj|jtj|tj|}|dkr0t|S)Nr)rrbpf_lookup_elemrr]rrS)rrrrr0r0r6 __getitem__os zTableBase.__getitem__cCsDtj|jtj|tj|d}|dkr@tjtj}td|dS)NrzCould not update table: %s) rbpf_update_elemrr]rosstrerror get_errnor)rrrrerrstrr0r0r6 __setitem__vszTableBase.__setitem__cCs$tj|jtj|}|dkr tdS)Nr)rZbpf_delete_elemrr]rrS)rrrr0r0r6 __delitem__|szTableBase.__delitem__c cs6x0|D](}y||VWqtk r,YqXqWdS)N)rS)rrr0r0r6 itervaluess  zTableBase.itervaluesc cs:x4|D],}y|||fVWqtk r0YqXqWdS)N)rS)rrr0r0r6 iteritemss  zTableBase.iteritemscCsdd|jDS)NcSsg|]}|qSr0r0).0itemr0r0r6 sz#TableBase.items..)r)rr0r0r6itemsszTableBase.itemscCsdd|jDS)NcSsg|]}|qSr0r0)rrr0r0r6rsz$TableBase.values..)r)rr0r0r6valuesszTableBase.valuescCs x|jD]}|j|q WdS)N)keysr)rkr0r0r6clearszTableBase.clearFcCszd}}| r$| r$tjdddfS|s0|j}n|dksB||jkrJtd|rZ|j|}|rj|j|}tj|||fS)aAllocate keys and/or values arrays. Useful for in items_*_batch. Args: alloc_k (bool): True to allocate keys array, False otherwise. Default is False. alloc_v (bool): True to allocate values array, False otherwise. Default is False. count (int): number of elements in the array(s) to allocate. If count is None then it allocates the maximum number of elements i.e self.max_entries. Returns: tuple: (count, keys, values). Where count is ct.c_uint32, and keys and values an instance of ct.Array Raises: ValueError: If count is less than 1 or greater than self.max_entries. Nrrz Wrong count)r]c_uint32r ValueErrorrr)ralloc_kalloc_vr8rrr0r0r6_alloc_keys_valuess   zTableBase._alloc_keys_valuescCsvd}xF||gD]:}|rt|tjs&tt|}|dks@||jkrtdqW|rl|rlt|t|krltdtj|S)aCheck if the given keys or values have the right type and size. Args: keys (ct.Array): keys array to check values (ct.Array): values array to check Returns: ct.c_uint32 : the size of the array(s) Raises: ValueError: If length of arrays is less than 1 or greater than self.max_entries, or when both arrays length are different. TypeError: If the keys and values are not an instance of ct.Array rrzArray's length is wrongz(keys array length != values array length) isinstancer]rt TypeErrorr<rrr)rrrZarr_lenelemr0r0r6_sanity_check_keys_valuess   z#TableBase._sanity_check_keys_valuesccs(x"|jddD]\}}||fVqWdS)aLook up all the key-value pairs in the map. Args: None Yields: tuple: The tuple of (key,value) for every entries that have been looked up. Notes: lookup batch on a keys subset is not supported by the kernel. F)deleteN))_items_lookup_and_optionally_delete_batch)rrrLr0r0r6items_lookup_batchs zTableBase.items_lookup_batchcCsh|dk rP|j|d}tj|jtj|tj|}|dkrdtdtjtj nx|j D]}dSWdS)aDelete the key-value pairs related to the keys given as parameters. Note that if no key are given, it is faster to call lib.bpf_lookup_and_delete_batch than create keys array and then call lib.bpf_delete_batch on these keys. Args: ct_keys (ct.Array): keys array to delete. If an array of keys is given then it deletes all the related keys-values. If keys is None (default) then it deletes all entries. Yields: tuple: The tuple of (key,value) for every entries that have been deleted. Raises: Exception: If bpf syscall return value indicates an error. N)rrz#BPF_MAP_DELETE_BATCH has failed: %s) rrZbpf_delete_batchrr]rrrrritems_lookup_and_delete_batch)rct_keysct_cntr_r0r0r6items_delete_batchs  zTableBase.items_delete_batchcCsT|j||d}tj|jtj|tj|tj|}|dkrPtdtjtj dS)aqUpdate all the key-value pairs in the map provided. The arrays must be the same length, between 1 and the maximum number of entries. Args: ct_keys (ct.Array): keys array to update ct_values (ct.Array): values array to update Raises: Exception: If bpf syscall return value indicates an error. )rrrz#BPF_MAP_UPDATE_BATCH has failed: %sN) rrZbpf_update_batchrr]rrrrr)rr ct_valuesrrr0r0r6items_update_batch s  zTableBase.items_update_batchccs(x"|jddD]\}}||fVqWdS)a?Look up and delete all the key-value pairs in the map. Args: None Yields: tuple: The tuple of (key,value) for every entries that have been looked up and deleted. Notes: lookup and delete batch on a keys subset is not supported by the kernel. T)rN)r)rrrLr0r0r6r s z'TableBase.items_lookup_and_delete_batchTc cs4|dkrtj}d}n tj}d}|jddd\}}}tjd}}d} x|j| |_||j| rftj|ndtj|tj|tj |j | tj|tj |j | tj|} tj } | |j7} | dkr| t jkrtd|tj| f| dkrP| |jkrP|jdkrFPqFWx&td| D]} || || fVqWdS)aLook up and optionally delete all the key-value pairs in the map. Args: delete (bool) : look up and delete the key-value pairs when True, else just look up. Yields: tuple: The tuple of (key,value) for every entries that have been looked up and deleted. Raises: Exception: If bpf syscall return value indicates an error. Notes: lookup and delete batch on a keys subset is not supported by the kernel. TZBPF_MAP_LOOKUP_AND_DELETE_BATCHZBPF_MAP_LOOKUP_BATCH)rrrNz%s has failed: %s)rZbpf_lookup_and_delete_batchZbpf_lookup_batchrr]rrrrrrrrerrnoENOENTrrrr;) rrZ bpf_batchZbpf_cmdZ ct_buf_sizerrZ ct_out_batchrZtotalrZerrcoder4r0r0r6r/s<     z3TableBase._items_lookup_and_optionally_delete_batchcCs&x t|jD]}|j||<qWdS)N)listrr)rrr0r0r6zerofszTableBase.zerocCs tj|S)N)rIter)rr0r0r6__iter__nszTableBase.__iter__cCs|jS)N)r)rr0r0r6iterqszTableBase.itercCs|jS)N)r)rr0r0r6rrszTableBase.keysc@s,eZdZddZddZddZddZd S) zTableBase.ItercCs||_d|_dS)N)tabler)rrr0r0r6ruszTableBase.Iter.__init__cCs|S)Nr0)rr0r0r6rxszTableBase.Iter.__iter__cCs|jS)N)next)rr0r0r6__next__zszTableBase.Iter.__next__cCs|jj|j|_|jS)N)rrr)rr0r0r6r|szTableBase.Iter.nextN)__name__ __module__ __qualname__rrrrr0r0r0r6rtsrcCs^|j}|dkr0tj|jtj|tj|j}ntj|jtj|tj|}|dkrZt|S)Nr) rrZbpf_get_first_keyrr]rrZbpf_get_next_key StopIteration)rrZnext_keyrr0r0r6rs zTableBase.nextc Cs|jjdd}|jjdd}|dkrHt|jjdkrH|jjdd}xX|jD]L\}}t||} |rp|| } |j| dgt} || <t||} |j| | <qRWt|j } |r|| } x| D]} |j | qWdS)NrrZ__pad_1rr) rr\r<rgetattrgetlog2_index_maxrrrr>) rtmpbuckets bucket_fnbucket_sort_fnf1f2rrLbucketr@ZslotZ buckets_lstr0r0r6decode_c_structs     zTableBase.decode_c_structr Bucket ptrc Cst|jtjrfi}g}|j||||xr|D]2}||} |rL|||f} n||f} t| || q.Wn6dgt} x |jD]\} } | j| | j<qzWt| |dS)a.print_json_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, bucket_sort_fn=None): Prints a table as a json histogram. The table must be stored as log2. The val_type argument is optional, and is a column header. If the histogram has a secondary key, the dictionary will be split by secondary key If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is log2_index_max (65), which will accommodate any 64-bit integer in the histogram. rN) rrr]rlrrDrrr) rr9section_headersection_print_fnrrrrrr@rArrLr0r0r6print_json_hists  zTableBase.print_json_histc Cst|jtjrvi}g}|j||||x|D]B} || } |rTtd||| fntd|| ft| ||q.Wn8dgt} x |jD]\} } | j | | j <qWt| ||dS)aprint_log2_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None): Prints a table as a log2 histogram. The table must be stored as log2. The val_type argument is optional, and is a column header. If the histogram has a secondary key, multiple tables will print and section_header can be used as a header description for each. If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If the value of strip_leading_zero is not False, prints a histogram that is omitted leading zeros from the beginning. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is log2_index_max (65), which will accommodate any 64-bit integer in the histogram. z %s = %sz %s = %rrN) rrr]rlrr?rPrrr) rr9rrrrIrrrrr@rrLr0r0r6print_log2_hists  zTableBase.print_log2_histc Cst|jtjrvi}g}|j||||x|D]B} || } |rTtd||| fntd|| ft| ||q.Wnddgt} xL|jD]@\} } y| j | | j <Wqt k rt d| j tfYqXqWt| ||dS)aprint_linear_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None) Prints a table as a linear histogram. This is intended to span integer ranges, eg, from 0 to 100. The val_type argument is optional, and is a column header. If the histogram has a secondary key, multiple tables will print and section_header can be used as a header description for each. If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If the value of strip_leading_zero is not False, prints a histogram that is omitted leading zeros from the beginning. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is linear_index_max (1025), which is hoped to be sufficient for integer ranges spanned. z %s = %sz %s = %rrz#Index in print_linear_hist() of %d zexceeds max of %d.Nz5Index in print_linear_hist() of %d exceeds max of %d.) rrr]rlrr?rQlinear_index_maxrr IndexError) rr9rrrrIrrrrr@rrLr0r0r6print_linear_hists&  zTableBase.print_linear_hist)N)FFN)NN)N)T)rrNNN)rrNNNN)rrNNNN)#rrrrrrrrrrrrrrrrrrrrrrrrrrrrobjectrrrrrrr0r0r0r6r=sH   #   7  # &rcs$eZdZfddZddZZS)rrcstt|j||dS)N)superrrr)rargsr) __class__r0r6r"szHashTable.__init__cCsd}x|D] }|d7}q W|S)Nrrr0)rr4rr0r0r6__len__%s zHashTable.__len__)rrrrr __classcell__r0r0)rr6rr!s rrcseZdZfddZZS)rcstt|j||dS)N)rrr)rrr)rr0r6r+szLruHash.__init__)rrrrrr0r0)rr6r*srcspeZdZfddZddZddZfddZfd d Zfd d Zd dZ ddZ Gddde Z Z S) ArrayBasecstt|j||dS)N)rrr)rrr)rr0r6r/szArrayBase.__init__cCsVt|tr(|dkrt||}|j|}t|tjs||d@dkrtdx tD]}|j|||||q WdS)azopen_perf_buffers(callback) Opens a set of per-cpu ring buffer to receive custom perf event data from the bpf program. The callback will be invoked for each event submitted from the kernel, up to millions per second. Use page_cnt to change the size of the per-cpu ring buffer. The value must be a power of two and defaults to 8. rrz+Perf buffer page_cnt must be a power of twoN)rr _open_perf_buffer)rcallbackpage_cntlost_cb wakeup_eventsr4r0r0r6open_perf_buffers  zPerfEventArray.open_perf_bufferc sfdd}fdd}t|}r.t|n tjdt} t} d| _| _|| _tj || d|tj | } | svt dtj | } |j | ||j<| |jjt|f<|| f|j<d|j<dS) NcsPy||Wn:tk rJ}z|jtjkr6tn|WYdd}~XnXdS)N)IOErrorrEPIPErj)rr:sizee)rcpur0r6raw_cb_s  z1PerfEventArray._open_perf_buffer..raw_cb_csLy |Wn:tk rF}z|jtjkr2tn|WYdd}~XnXdS)N)r"rr#rj)rZlostr%)rr0r6lost_cb_s   z2PerfEventArray._open_perf_buffer..lost_cb_rzCould not open perf bufferr/r/)rr r]rr pidr&r rZbpf_open_perf_buffer_optsrrZperf_reader_fdrrrbrrrr) rr&rrrr r'r(fnZlost_fnZoptsreaderr r0)rr&rr6rs   z PerfEventArray._open_perf_buffercCsBtj||d|}|dkr td|j|||j|<||j|<dS)Nrrzbpf_open_perf_event failedr/)rZbpf_open_perf_eventrrrr)rr&typconfigr r0r0r6_open_perf_events zPerfEventArray._open_perf_eventcCs"xtD]}|j|||qWdS)zopen_perf_event(typ, config) Configures the table such that calls from the bpf program to table.perf_read(CUR_CPU_IDENTIFIER) will return the hardware counter denoted by event ev on the local cpu. N)r r.)rr,r-r4r0r0r6open_perf_events zPerfEventArray.open_perf_event)rNr) rrrrr rrr!rr.r/rr0r0)rr6rxs   "rxcsTeZdZfddZfddZddZfddZd d Zd d Zd dZ Z S)rzcs|jdd|_tt|j|||j|_tt|_ t j |jd|_ |j dkr`|j|j |_n@|jt j kr|t j|j |_n$|jt jkrt j|j |_ntddS)NreducerrrzLeaf must be aligned to 8 bytes)popr0rrzrrsLeafr<r total_cpur]r alignmentr_c_uint64r^c_int64r)rrr)rr0r6rs    zPerCpuHash.__init__csTtt|j|}|jdkr |}n0|j|j}x td|jD]}||||<q.ringbuf_cb_rN)r rbZ_open_ring_bufferrr)rrrHrIr*r0)rr6open_ring_buffers zRingBuf.open_ring_buffer)N) rrrrZ_RingBuf__delitemr rrrJrr0r0)rr6rs   rc@sReZdZdZddZddZddZdd d Zd d Zd dZ ddZ ddZ dS)rrcCs\||_||_||_||_tj|jj|j|_tj|jj|j|_ t tj |jj|j|_ dS)N) rbrrrrrprcrTrrr=rr)rrbrrrr0r0r6rs zQueueStack.__init__cCsNtjtj|jd}tj|jj|j|t |tj |}|dkrHt d|j S)NrrzCould not printf leaf) r]rrrrrrbrcrr<rrr)rrrrr0r0r6rs zQueueStack.leaf_sprintfcCs8|j}tj|jj|j|tj|}|dkr4td|S)NrzCould not scanf leaf) rrrrbrcrr]rr)rrrrr0r0r6rs  zQueueStack.leaf_scanfrcCs>tj|jdtj||}|dkr:tjtj}td|dS)NrzCould not push to table: %s) rrrr]rrrrr)rrrrrr0r0r6pushszQueueStack.pushcCs2|j}tj|jdtj|}|dkr.td|S)NrzCould not pop from table)rrZbpf_lookup_and_deleterr]rrS)rrrr0r0r6r1$s zQueueStack.popcCs2|j}tj|jdtj|}|dkr.td|S)NrzCould not peek table)rrrrr]rrS)rrrr0r0r6peek+s zQueueStack.peekc cs@|j}x4|r:y|jV|d8}Wqtk r6dSXqWdS)Nr)rr1rS)rZcntr0r0r6r2s  zQueueStack.itervaluescCsdd|jDS)NcSsg|]}|qSr0r0)rrr0r0r6r=sz%QueueStack.values..)r)rr0r0r6r<szQueueStack.valuesN)r) rrrZ BPF_EXISTrrrrKr1rLrrr0r0r0r6rs   r)N)VZ __future__rcollections.abcr ImportError collectionsZtimerZctypesr] functoolsrrrr`rhZlibbccrrr r r Zutilsr r rqrsrurwryr{rrrrr}rrrZBPF_MAP_TYPE_SOCKMAPrrZBPF_MAP_TYPE_SOCKHASHZBPF_MAP_TYPE_CGROUP_STORAGEZ BPF_MAP_TYPE_REUSEPORT_SOCKARRAYZ"BPF_MAP_TYPE_PERCPU_CGROUP_STORAGErrZBPF_MAP_TYPE_SK_STORAGEZBPF_MAP_TYPE_DEVMAP_HASHZBPF_MAP_TYPE_STRUCT_OPSrZBPF_MAP_TYPE_INODE_STORAGEZBPF_MAP_TYPE_TASK_STORAGErRrHrrr7rDrPrQrUrorrrrrrrtrvr rrxrzrr|r~rrrrrrrrr0r0r0r6s      &;0g 8 l4849table.py000064400000137744152344707330006235 0ustar00# Copyright 2015 PLUMgrid # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function try: from collections.abc import MutableMapping except ImportError: from collections import MutableMapping from time import strftime import ctypes as ct from functools import reduce import os import errno import re import sys from .libbcc import lib, _RAW_CB_TYPE, _LOST_CB_TYPE, _RINGBUF_CB_TYPE, bcc_perf_buffer_opts from .utils import get_online_cpus from .utils import get_possible_cpus BPF_MAP_TYPE_HASH = 1 BPF_MAP_TYPE_ARRAY = 2 BPF_MAP_TYPE_PROG_ARRAY = 3 BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4 BPF_MAP_TYPE_PERCPU_HASH = 5 BPF_MAP_TYPE_PERCPU_ARRAY = 6 BPF_MAP_TYPE_STACK_TRACE = 7 BPF_MAP_TYPE_CGROUP_ARRAY = 8 BPF_MAP_TYPE_LRU_HASH = 9 BPF_MAP_TYPE_LRU_PERCPU_HASH = 10 BPF_MAP_TYPE_LPM_TRIE = 11 BPF_MAP_TYPE_ARRAY_OF_MAPS = 12 BPF_MAP_TYPE_HASH_OF_MAPS = 13 BPF_MAP_TYPE_DEVMAP = 14 BPF_MAP_TYPE_SOCKMAP = 15 BPF_MAP_TYPE_CPUMAP = 16 BPF_MAP_TYPE_XSKMAP = 17 BPF_MAP_TYPE_SOCKHASH = 18 BPF_MAP_TYPE_CGROUP_STORAGE = 19 BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 20 BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 21 BPF_MAP_TYPE_QUEUE = 22 BPF_MAP_TYPE_STACK = 23 BPF_MAP_TYPE_SK_STORAGE = 24 BPF_MAP_TYPE_DEVMAP_HASH = 25 BPF_MAP_TYPE_STRUCT_OPS = 26 BPF_MAP_TYPE_RINGBUF = 27 BPF_MAP_TYPE_INODE_STORAGE = 28 BPF_MAP_TYPE_TASK_STORAGE = 29 map_type_name = { BPF_MAP_TYPE_HASH: "HASH", BPF_MAP_TYPE_ARRAY: "ARRAY", BPF_MAP_TYPE_PROG_ARRAY: "PROG_ARRAY", BPF_MAP_TYPE_PERF_EVENT_ARRAY: "PERF_EVENT_ARRAY", BPF_MAP_TYPE_PERCPU_HASH: "PERCPU_HASH", BPF_MAP_TYPE_PERCPU_ARRAY: "PERCPU_ARRAY", BPF_MAP_TYPE_STACK_TRACE: "STACK_TRACE", BPF_MAP_TYPE_CGROUP_ARRAY: "CGROUP_ARRAY", BPF_MAP_TYPE_LRU_HASH: "LRU_HASH", BPF_MAP_TYPE_LRU_PERCPU_HASH: "LRU_PERCPU_HASH", BPF_MAP_TYPE_LPM_TRIE: "LPM_TRIE", BPF_MAP_TYPE_ARRAY_OF_MAPS: "ARRAY_OF_MAPS", BPF_MAP_TYPE_HASH_OF_MAPS: "HASH_OF_MAPS", BPF_MAP_TYPE_DEVMAP: "DEVMAP", BPF_MAP_TYPE_SOCKMAP: "SOCKMAP", BPF_MAP_TYPE_CPUMAP: "CPUMAP", BPF_MAP_TYPE_XSKMAP: "XSKMAP", BPF_MAP_TYPE_SOCKHASH: "SOCKHASH", BPF_MAP_TYPE_CGROUP_STORAGE: "CGROUP_STORAGE", BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: "REUSEPORT_SOCKARRAY", BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: "PERCPU_CGROUP_STORAGE", BPF_MAP_TYPE_QUEUE: "QUEUE", BPF_MAP_TYPE_STACK: "STACK", BPF_MAP_TYPE_SK_STORAGE: "SK_STORAGE", BPF_MAP_TYPE_DEVMAP_HASH: "DEVMAP_HASH", BPF_MAP_TYPE_STRUCT_OPS: "STRUCT_OPS", BPF_MAP_TYPE_RINGBUF: "RINGBUF", BPF_MAP_TYPE_INODE_STORAGE: "INODE_STORAGE", BPF_MAP_TYPE_TASK_STORAGE: "TASK_STORAGE", } stars_max = 40 log2_index_max = 65 linear_index_max = 1025 # helper functions, consider moving these to a utils module def _stars(val, val_max, width): i = 0 text = "" while (1): if (i > (width * val / val_max) - 1) or (i > width - 1): break text += "*" i += 1 if val > val_max: text = text[:-1] + "+" return text def _print_json_hist(vals, val_type, section_bucket=None): hist_list = [] max_nonzero_idx = 0 for i in range(len(vals)): if vals[i] != 0: max_nonzero_idx = i index = 1 prev = 0 for i in range(len(vals)): if i != 0 and i <= max_nonzero_idx: index = index * 2 list_obj = {} list_obj['interval-start'] = prev list_obj['interval-end'] = int(index) - 1 list_obj['count'] = int(vals[i]) hist_list.append(list_obj) prev = index histogram = {"ts": strftime("%Y-%m-%d %H:%M:%S"), "val_type": val_type, "data": hist_list} if section_bucket: histogram[section_bucket[0]] = section_bucket[1] print(histogram) def _print_log2_hist(vals, val_type, strip_leading_zero): global stars_max log2_dist_max = 64 idx_max = -1 val_max = 0 for i, v in enumerate(vals): if v > 0: idx_max = i if v > val_max: val_max = v if idx_max <= 32: header = " %-19s : count distribution" body = "%10d -> %-10d : %-8d |%-*s|" stars = stars_max else: header = " %-29s : count distribution" body = "%20d -> %-20d : %-8d |%-*s|" stars = int(stars_max / 2) if idx_max > 0: print(header % val_type) for i in range(1, idx_max + 1): low = (1 << i) >> 1 high = (1 << i) - 1 if (low == high): low -= 1 val = vals[i] if strip_leading_zero: if val: print(body % (low, high, val, stars, _stars(val, val_max, stars))) strip_leading_zero = False else: print(body % (low, high, val, stars, _stars(val, val_max, stars))) def _print_linear_hist(vals, val_type, strip_leading_zero): global stars_max log2_dist_max = 64 idx_max = -1 val_max = 0 for i, v in enumerate(vals): if v > 0: idx_max = i if v > val_max: val_max = v header = " %-13s : count distribution" body = " %-10d : %-8d |%-*s|" stars = stars_max if idx_max >= 0: print(header % val_type) for i in range(0, idx_max + 1): val = vals[i] if strip_leading_zero: if val: print(body % (i, val, stars, _stars(val, val_max, stars))) strip_leading_zero = False else: print(body % (i, val, stars, _stars(val, val_max, stars))) def get_table_type_name(ttype): try: return map_type_name[ttype] except KeyError: return "" def _get_event_class(event_map): ct_mapping = { 'char' : ct.c_char, 's8' : ct.c_char, 'unsigned char' : ct.c_ubyte, 'u8' : ct.c_ubyte, 'u8 *' : ct.c_char_p, 'char *' : ct.c_char_p, 'short' : ct.c_short, 's16' : ct.c_short, 'unsigned short' : ct.c_ushort, 'u16' : ct.c_ushort, 'int' : ct.c_int, 's32' : ct.c_int, 'enum' : ct.c_int, 'unsigned int' : ct.c_uint, 'u32' : ct.c_uint, 'long' : ct.c_long, 'unsigned long' : ct.c_ulong, 'long long' : ct.c_longlong, 's64' : ct.c_longlong, 'unsigned long long': ct.c_ulonglong, 'u64' : ct.c_ulonglong, '__int128' : (ct.c_longlong * 2), 'unsigned __int128' : (ct.c_ulonglong * 2), 'void *' : ct.c_void_p, } # handle array types e.g. "int [16]" or "char[16]" array_type = re.compile(r"([^ ]+) ?\[([0-9]+)\]$") fields = [] num_fields = lib.bpf_perf_event_fields(event_map.bpf.module, event_map._name) i = 0 while i < num_fields: field = lib.bpf_perf_event_field(event_map.bpf.module, event_map._name, i).decode() m = re.match(r"(.*)#(.*)", field) field_name = m.group(1) field_type = m.group(2) if re.match(r"enum .*", field_type): field_type = "enum" m = array_type.match(field_type) try: if m: fields.append((field_name, ct_mapping[m.group(1)] * int(m.group(2)))) else: fields.append((field_name, ct_mapping[field_type])) except KeyError: # Using print+sys.exit instead of raising exceptions, # because exceptions are caught by the caller. print("Type: '%s' not recognized. Please define the data with ctypes manually." % field_type, file=sys.stderr) sys.exit(1) i += 1 return type('', (ct.Structure,), {'_fields_': fields}) def Table(bpf, map_id, map_fd, keytype, leaftype, name, **kwargs): """Table(bpf, map_id, map_fd, keytype, leaftype, **kwargs) Create a python object out of a reference to a bpf table handle""" ttype = lib.bpf_table_type_id(bpf.module, map_id) t = None if ttype == BPF_MAP_TYPE_HASH: t = HashTable(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_ARRAY: t = Array(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_PROG_ARRAY: t = ProgArray(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_PERF_EVENT_ARRAY: t = PerfEventArray(bpf, map_id, map_fd, keytype, leaftype, name) elif ttype == BPF_MAP_TYPE_PERCPU_HASH: t = PerCpuHash(bpf, map_id, map_fd, keytype, leaftype, **kwargs) elif ttype == BPF_MAP_TYPE_PERCPU_ARRAY: t = PerCpuArray(bpf, map_id, map_fd, keytype, leaftype, **kwargs) elif ttype == BPF_MAP_TYPE_LPM_TRIE: t = LpmTrie(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_STACK_TRACE: t = StackTrace(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_LRU_HASH: t = LruHash(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_LRU_PERCPU_HASH: t = LruPerCpuHash(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_CGROUP_ARRAY: t = CgroupArray(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_DEVMAP: t = DevMap(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_CPUMAP: t = CpuMap(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_XSKMAP: t = XskMap(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_ARRAY_OF_MAPS: t = MapInMapArray(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_HASH_OF_MAPS: t = MapInMapHash(bpf, map_id, map_fd, keytype, leaftype) elif ttype == BPF_MAP_TYPE_QUEUE or ttype == BPF_MAP_TYPE_STACK: t = QueueStack(bpf, map_id, map_fd, leaftype) elif ttype == BPF_MAP_TYPE_RINGBUF: t = RingBuf(bpf, map_id, map_fd, keytype, leaftype, name) if t == None: raise Exception("Unknown table type %d" % ttype) return t class TableBase(MutableMapping): def __init__(self, bpf, map_id, map_fd, keytype, leaftype, name=None): self.bpf = bpf self.map_id = map_id self.map_fd = map_fd self.Key = keytype self.Leaf = leaftype self.ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id) self.flags = lib.bpf_table_flags_id(self.bpf.module, self.map_id) self._cbs = {} self._name = name self.max_entries = int(lib.bpf_table_max_entries_id(self.bpf.module, self.map_id)) def get_fd(self): return self.map_fd def key_sprintf(self, key): buf = ct.create_string_buffer(ct.sizeof(self.Key) * 8) res = lib.bpf_table_key_snprintf(self.bpf.module, self.map_id, buf, len(buf), ct.byref(key)) if res < 0: raise Exception("Could not printf key") return buf.value def leaf_sprintf(self, leaf): buf = ct.create_string_buffer(ct.sizeof(self.Leaf) * 8) res = lib.bpf_table_leaf_snprintf(self.bpf.module, self.map_id, buf, len(buf), ct.byref(leaf)) if res < 0: raise Exception("Could not printf leaf") return buf.value def key_scanf(self, key_str): key = self.Key() res = lib.bpf_table_key_sscanf(self.bpf.module, self.map_id, key_str, ct.byref(key)) if res < 0: raise Exception("Could not scanf key") return key def leaf_scanf(self, leaf_str): leaf = self.Leaf() res = lib.bpf_table_leaf_sscanf(self.bpf.module, self.map_id, leaf_str, ct.byref(leaf)) if res < 0: raise Exception("Could not scanf leaf") return leaf def __getitem__(self, key): leaf = self.Leaf() res = lib.bpf_lookup_elem(self.map_fd, ct.byref(key), ct.byref(leaf)) if res < 0: raise KeyError return leaf def __setitem__(self, key, leaf): res = lib.bpf_update_elem(self.map_fd, ct.byref(key), ct.byref(leaf), 0) if res < 0: errstr = os.strerror(ct.get_errno()) raise Exception("Could not update table: %s" % errstr) def __delitem__(self, key): res = lib.bpf_delete_elem(self.map_fd, ct.byref(key)) if res < 0: raise KeyError # override the MutableMapping's implementation of these since they # don't handle KeyError nicely def itervalues(self): for key in self: # a map entry may be deleted in between discovering the key and # fetching the value, suppress such errors try: yield self[key] except KeyError: pass def iteritems(self): for key in self: try: yield (key, self[key]) except KeyError: pass def items(self): return [item for item in self.iteritems()] def values(self): return [value for value in self.itervalues()] def clear(self): # default clear uses popitem, which can race with the bpf prog for k in self.keys(): self.__delitem__(k) def _alloc_keys_values(self, alloc_k=False, alloc_v=False, count=None): """Allocate keys and/or values arrays. Useful for in items_*_batch. Args: alloc_k (bool): True to allocate keys array, False otherwise. Default is False. alloc_v (bool): True to allocate values array, False otherwise. Default is False. count (int): number of elements in the array(s) to allocate. If count is None then it allocates the maximum number of elements i.e self.max_entries. Returns: tuple: (count, keys, values). Where count is ct.c_uint32, and keys and values an instance of ct.Array Raises: ValueError: If count is less than 1 or greater than self.max_entries. """ keys = values = None if not alloc_k and not alloc_v: return (ct.c_uint32(0), None, None) if not count: # means alloc maximum size count = self.max_entries elif count < 1 or count > self.max_entries: raise ValueError("Wrong count") if alloc_k: keys = (self.Key * count)() if alloc_v: values = (self.Leaf * count)() return (ct.c_uint32(count), keys, values) def _sanity_check_keys_values(self, keys=None, values=None): """Check if the given keys or values have the right type and size. Args: keys (ct.Array): keys array to check values (ct.Array): values array to check Returns: ct.c_uint32 : the size of the array(s) Raises: ValueError: If length of arrays is less than 1 or greater than self.max_entries, or when both arrays length are different. TypeError: If the keys and values are not an instance of ct.Array """ arr_len = 0 for elem in [keys, values]: if elem: if not isinstance(elem, ct.Array): raise TypeError arr_len = len(elem) if arr_len < 1 or arr_len > self.max_entries: raise ValueError("Array's length is wrong") if keys and values: # check both length are equal if len(keys) != len(values): raise ValueError("keys array length != values array length") return ct.c_uint32(arr_len) def items_lookup_batch(self): """Look up all the key-value pairs in the map. Args: None Yields: tuple: The tuple of (key,value) for every entries that have been looked up. Notes: lookup batch on a keys subset is not supported by the kernel. """ for k, v in self._items_lookup_and_optionally_delete_batch(delete=False): yield(k, v) return def items_delete_batch(self, ct_keys=None): """Delete the key-value pairs related to the keys given as parameters. Note that if no key are given, it is faster to call lib.bpf_lookup_and_delete_batch than create keys array and then call lib.bpf_delete_batch on these keys. Args: ct_keys (ct.Array): keys array to delete. If an array of keys is given then it deletes all the related keys-values. If keys is None (default) then it deletes all entries. Yields: tuple: The tuple of (key,value) for every entries that have been deleted. Raises: Exception: If bpf syscall return value indicates an error. """ if ct_keys is not None: ct_cnt = self._sanity_check_keys_values(keys=ct_keys) res = lib.bpf_delete_batch(self.map_fd, ct.byref(ct_keys), ct.byref(ct_cnt) ) if (res != 0): raise Exception("BPF_MAP_DELETE_BATCH has failed: %s" % os.strerror(ct.get_errno())) else: for _ in self.items_lookup_and_delete_batch(): return def items_update_batch(self, ct_keys, ct_values): """Update all the key-value pairs in the map provided. The arrays must be the same length, between 1 and the maximum number of entries. Args: ct_keys (ct.Array): keys array to update ct_values (ct.Array): values array to update Raises: Exception: If bpf syscall return value indicates an error. """ ct_cnt = self._sanity_check_keys_values(keys=ct_keys, values=ct_values) res = lib.bpf_update_batch(self.map_fd, ct.byref(ct_keys), ct.byref(ct_values), ct.byref(ct_cnt) ) if (res != 0): raise Exception("BPF_MAP_UPDATE_BATCH has failed: %s" % os.strerror(ct.get_errno())) def items_lookup_and_delete_batch(self): """Look up and delete all the key-value pairs in the map. Args: None Yields: tuple: The tuple of (key,value) for every entries that have been looked up and deleted. Notes: lookup and delete batch on a keys subset is not supported by the kernel. """ for k, v in self._items_lookup_and_optionally_delete_batch(delete=True): yield(k, v) return def _items_lookup_and_optionally_delete_batch(self, delete=True): """Look up and optionally delete all the key-value pairs in the map. Args: delete (bool) : look up and delete the key-value pairs when True, else just look up. Yields: tuple: The tuple of (key,value) for every entries that have been looked up and deleted. Raises: Exception: If bpf syscall return value indicates an error. Notes: lookup and delete batch on a keys subset is not supported by the kernel. """ if delete is True: bpf_batch = lib.bpf_lookup_and_delete_batch bpf_cmd = "BPF_MAP_LOOKUP_AND_DELETE_BATCH" else: bpf_batch = lib.bpf_lookup_batch bpf_cmd = "BPF_MAP_LOOKUP_BATCH" # alloc keys and values to the max size ct_buf_size, ct_keys, ct_values = self._alloc_keys_values(alloc_k=True, alloc_v=True) ct_out_batch = ct_cnt = ct.c_uint32(0) total = 0 while True: ct_cnt.value = ct_buf_size.value - total res = bpf_batch(self.map_fd, ct.byref(ct_out_batch) if total else None, ct.byref(ct_out_batch), ct.byref(ct_keys, ct.sizeof(self.Key) * total), ct.byref(ct_values, ct.sizeof(self.Leaf) * total), ct.byref(ct_cnt) ) errcode = ct.get_errno() total += ct_cnt.value if (res != 0 and errcode != errno.ENOENT): raise Exception("%s has failed: %s" % (bpf_cmd, os.strerror(errcode))) if res != 0: break # success if total == ct_buf_size.value: # buffer full, we can't progress break if ct_cnt.value == 0: # no progress, probably because concurrent update # puts too many elements in one bucket. break for i in range(0, total): yield (ct_keys[i], ct_values[i]) def zero(self): # Even though this is not very efficient, we grab the entire list of # keys before enumerating it. This helps avoid a potential race where # the leaf assignment changes a hash table bucket that is being # enumerated by the same loop, and may lead to a hang. for k in list(self.keys()): self[k] = self.Leaf() def __iter__(self): return TableBase.Iter(self) def iter(self): return self.__iter__() def keys(self): return self.__iter__() class Iter(object): def __init__(self, table): self.table = table self.key = None def __iter__(self): return self def __next__(self): return self.next() def next(self): self.key = self.table.next(self.key) return self.key def next(self, key): next_key = self.Key() if key is None: res = lib.bpf_get_first_key(self.map_fd, ct.byref(next_key), ct.sizeof(self.Key)) else: res = lib.bpf_get_next_key(self.map_fd, ct.byref(key), ct.byref(next_key)) if res < 0: raise StopIteration() return next_key def decode_c_struct(self, tmp, buckets, bucket_fn, bucket_sort_fn): f1 = self.Key._fields_[0][0] f2 = self.Key._fields_[1][0] # The above code assumes that self.Key._fields_[1][0] holds the # slot. But a padding member may have been inserted here, which # breaks the assumption and leads to chaos. # TODO: this is a quick fix. Fixing/working around in the BCC # internal library is the right thing to do. if f2 == '__pad_1' and len(self.Key._fields_) == 3: f2 = self.Key._fields_[2][0] for k, v in self.items(): bucket = getattr(k, f1) if bucket_fn: bucket = bucket_fn(bucket) vals = tmp[bucket] = tmp.get(bucket, [0] * log2_index_max) slot = getattr(k, f2) vals[slot] = v.value buckets_lst = list(tmp.keys()) if bucket_sort_fn: buckets_lst = bucket_sort_fn(buckets_lst) for bucket in buckets_lst: buckets.append(bucket) def print_json_hist(self, val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, bucket_sort_fn=None): """print_json_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, bucket_sort_fn=None): Prints a table as a json histogram. The table must be stored as log2. The val_type argument is optional, and is a column header. If the histogram has a secondary key, the dictionary will be split by secondary key If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is log2_index_max (65), which will accommodate any 64-bit integer in the histogram. """ if isinstance(self.Key(), ct.Structure): tmp = {} buckets = [] self.decode_c_struct(tmp, buckets, bucket_fn, bucket_sort_fn) for bucket in buckets: vals = tmp[bucket] if section_print_fn: section_bucket = (section_header, section_print_fn(bucket)) else: section_bucket = (section_header, bucket) _print_json_hist(vals, val_type, section_bucket) else: vals = [0] * log2_index_max for k, v in self.items(): vals[k.value] = v.value _print_json_hist(vals, val_type) def print_log2_hist(self, val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None): """print_log2_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None): Prints a table as a log2 histogram. The table must be stored as log2. The val_type argument is optional, and is a column header. If the histogram has a secondary key, multiple tables will print and section_header can be used as a header description for each. If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If the value of strip_leading_zero is not False, prints a histogram that is omitted leading zeros from the beginning. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is log2_index_max (65), which will accommodate any 64-bit integer in the histogram. """ if isinstance(self.Key(), ct.Structure): tmp = {} buckets = [] self.decode_c_struct(tmp, buckets, bucket_fn, bucket_sort_fn) for bucket in buckets: vals = tmp[bucket] if section_print_fn: print("\n%s = %s" % (section_header, section_print_fn(bucket))) else: print("\n%s = %r" % (section_header, bucket)) _print_log2_hist(vals, val_type, strip_leading_zero) else: vals = [0] * log2_index_max for k, v in self.items(): vals[k.value] = v.value _print_log2_hist(vals, val_type, strip_leading_zero) def print_linear_hist(self, val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None): """print_linear_hist(val_type="value", section_header="Bucket ptr", section_print_fn=None, bucket_fn=None, strip_leading_zero=None, bucket_sort_fn=None) Prints a table as a linear histogram. This is intended to span integer ranges, eg, from 0 to 100. The val_type argument is optional, and is a column header. If the histogram has a secondary key, multiple tables will print and section_header can be used as a header description for each. If section_print_fn is not None, it will be passed the bucket value to format into a string as it sees fit. If bucket_fn is not None, it will be used to produce a bucket value for the histogram keys. If the value of strip_leading_zero is not False, prints a histogram that is omitted leading zeros from the beginning. If bucket_sort_fn is not None, it will be used to sort the buckets before iterating them, and it is useful when there are multiple fields in the secondary key. The maximum index allowed is linear_index_max (1025), which is hoped to be sufficient for integer ranges spanned. """ if isinstance(self.Key(), ct.Structure): tmp = {} buckets = [] self.decode_c_struct(tmp, buckets, bucket_fn, bucket_sort_fn) for bucket in buckets: vals = tmp[bucket] if section_print_fn: print("\n%s = %s" % (section_header, section_print_fn(bucket))) else: print("\n%s = %r" % (section_header, bucket)) _print_linear_hist(vals, val_type, strip_leading_zero) else: vals = [0] * linear_index_max for k, v in self.items(): try: vals[k.value] = v.value except IndexError: # Improve error text. If the limit proves a nusiance, this # function be rewritten to avoid having one. raise IndexError(("Index in print_linear_hist() of %d " + "exceeds max of %d.") % (k.value, linear_index_max)) _print_linear_hist(vals, val_type, strip_leading_zero) class HashTable(TableBase): def __init__(self, *args, **kwargs): super(HashTable, self).__init__(*args, **kwargs) def __len__(self): i = 0 for k in self: i += 1 return i class LruHash(HashTable): def __init__(self, *args, **kwargs): super(LruHash, self).__init__(*args, **kwargs) class ArrayBase(TableBase): def __init__(self, *args, **kwargs): super(ArrayBase, self).__init__(*args, **kwargs) def _normalize_key(self, key): if isinstance(key, int): if key < 0: key = len(self) + key key = self.Key(key) if not isinstance(key, ct._SimpleCData): raise IndexError("Array index must be an integer type") if key.value >= len(self): raise IndexError("Array index out of range") return key def __len__(self): return self.max_entries def __getitem__(self, key): key = self._normalize_key(key) return super(ArrayBase, self).__getitem__(key) def __setitem__(self, key, leaf): key = self._normalize_key(key) super(ArrayBase, self).__setitem__(key, leaf) def __delitem__(self, key): key = self._normalize_key(key) super(ArrayBase, self).__delitem__(key) def clearitem(self, key): key = self._normalize_key(key) leaf = self.Leaf() res = lib.bpf_update_elem(self.map_fd, ct.byref(key), ct.byref(leaf), 0) if res < 0: raise Exception("Could not clear item") def __iter__(self): return ArrayBase.Iter(self, self.Key) class Iter(object): def __init__(self, table, keytype): self.Key = keytype self.table = table self.i = -1 def __iter__(self): return self def __next__(self): return self.next() def next(self): self.i += 1 if self.i == len(self.table): raise StopIteration() return self.Key(self.i) class Array(ArrayBase): def __init__(self, *args, **kwargs): super(Array, self).__init__(*args, **kwargs) def __delitem__(self, key): # Delete in Array type does not have an effect, so zero out instead self.clearitem(key) class ProgArray(ArrayBase): def __init__(self, *args, **kwargs): super(ProgArray, self).__init__(*args, **kwargs) def __setitem__(self, key, leaf): if isinstance(leaf, int): leaf = self.Leaf(leaf) if isinstance(leaf, self.bpf.Function): leaf = self.Leaf(leaf.fd) super(ProgArray, self).__setitem__(key, leaf) class FileDesc: def __init__(self, fd): if (fd is None) or (fd < 0): raise Exception("Invalid file descriptor") self.fd = fd def clean_up(self): if (self.fd is not None) and (self.fd >= 0): os.close(self.fd) self.fd = None def __del__(self): self.clean_up() def __enter__(self, *args, **kwargs): return self def __exit__(self, *args, **kwargs): self.clean_up() class CgroupArray(ArrayBase): def __init__(self, *args, **kwargs): super(CgroupArray, self).__init__(*args, **kwargs) def __setitem__(self, key, leaf): if isinstance(leaf, int): super(CgroupArray, self).__setitem__(key, self.Leaf(leaf)) elif isinstance(leaf, str): # TODO: Add os.O_CLOEXEC once we move to Python version >3.3 with FileDesc(os.open(leaf, os.O_RDONLY)) as f: super(CgroupArray, self).__setitem__(key, self.Leaf(f.fd)) else: raise Exception("Cgroup array key must be either FD or cgroup path") class PerfEventArray(ArrayBase): def __init__(self, *args, **kwargs): super(PerfEventArray, self).__init__(*args, **kwargs) self._open_key_fds = {} self._event_class = None def __del__(self): keys = list(self._open_key_fds.keys()) for key in keys: del self[key] def __delitem__(self, key): if key not in self._open_key_fds: return # Delete entry from the array super(PerfEventArray, self).__delitem__(key) key_id = (id(self), key) if key_id in self.bpf.perf_buffers: # The key is opened for perf ring buffer lib.perf_reader_free(self.bpf.perf_buffers[key_id]) del self.bpf.perf_buffers[key_id] del self._cbs[key] else: # The key is opened for perf event read lib.bpf_close_perf_event_fd(self._open_key_fds[key]) del self._open_key_fds[key] def event(self, data): """event(data) When perf buffers are opened to receive custom perf event, the underlying event data struct which is defined in C in the BPF program can be deduced via this function. This avoids redundant definitions in Python. """ if self._event_class == None: self._event_class = _get_event_class(self) return ct.cast(data, ct.POINTER(self._event_class)).contents def open_perf_buffer(self, callback, page_cnt=8, lost_cb=None, wakeup_events=1): """open_perf_buffers(callback) Opens a set of per-cpu ring buffer to receive custom perf event data from the bpf program. The callback will be invoked for each event submitted from the kernel, up to millions per second. Use page_cnt to change the size of the per-cpu ring buffer. The value must be a power of two and defaults to 8. """ if page_cnt & (page_cnt - 1) != 0: raise Exception("Perf buffer page_cnt must be a power of two") for i in get_online_cpus(): self._open_perf_buffer(i, callback, page_cnt, lost_cb, wakeup_events) def _open_perf_buffer(self, cpu, callback, page_cnt, lost_cb, wakeup_events): def raw_cb_(_, data, size): try: callback(cpu, data, size) except IOError as e: if e.errno == errno.EPIPE: exit() else: raise e def lost_cb_(_, lost): try: lost_cb(lost) except IOError as e: if e.errno == errno.EPIPE: exit() else: raise e fn = _RAW_CB_TYPE(raw_cb_) lost_fn = _LOST_CB_TYPE(lost_cb_) if lost_cb else ct.cast(None, _LOST_CB_TYPE) opts = bcc_perf_buffer_opts() opts.pid = -1 opts.cpu = cpu opts.wakeup_events = wakeup_events reader = lib.bpf_open_perf_buffer_opts(fn, lost_fn, None, page_cnt, ct.byref(opts)) if not reader: raise Exception("Could not open perf buffer") fd = lib.perf_reader_fd(reader) self[self.Key(cpu)] = self.Leaf(fd) self.bpf.perf_buffers[(id(self), cpu)] = reader # keep a refcnt self._cbs[cpu] = (fn, lost_fn) # The actual fd is held by the perf reader, add to track opened keys self._open_key_fds[cpu] = -1 def _open_perf_event(self, cpu, typ, config): fd = lib.bpf_open_perf_event(typ, config, -1, cpu) if fd < 0: raise Exception("bpf_open_perf_event failed") self[self.Key(cpu)] = self.Leaf(fd) self._open_key_fds[cpu] = fd def open_perf_event(self, typ, config): """open_perf_event(typ, config) Configures the table such that calls from the bpf program to table.perf_read(CUR_CPU_IDENTIFIER) will return the hardware counter denoted by event ev on the local cpu. """ for i in get_online_cpus(): self._open_perf_event(i, typ, config) class PerCpuHash(HashTable): def __init__(self, *args, **kwargs): self.reducer = kwargs.pop("reducer", None) super(PerCpuHash, self).__init__(*args, **kwargs) self.sLeaf = self.Leaf self.total_cpu = len(get_possible_cpus()) # This needs to be 8 as hard coded into the linux kernel. self.alignment = ct.sizeof(self.sLeaf) % 8 if self.alignment == 0: self.Leaf = self.sLeaf * self.total_cpu else: # Currently Float, Char, un-aligned structs are not supported if self.sLeaf == ct.c_uint: self.Leaf = ct.c_uint64 * self.total_cpu elif self.sLeaf == ct.c_int: self.Leaf = ct.c_int64 * self.total_cpu else: raise IndexError("Leaf must be aligned to 8 bytes") def getvalue(self, key): result = super(PerCpuHash, self).__getitem__(key) if self.alignment == 0: ret = result else: ret = (self.sLeaf * self.total_cpu)() for i in range(0, self.total_cpu): ret[i] = result[i] return ret def __getitem__(self, key): if self.reducer: return reduce(self.reducer, self.getvalue(key)) else: return self.getvalue(key) def __setitem__(self, key, leaf): super(PerCpuHash, self).__setitem__(key, leaf) def sum(self, key): if isinstance(self.Leaf(), ct.Structure): raise IndexError("Leaf must be an integer type for default sum functions") return self.sLeaf(sum(self.getvalue(key))) def max(self, key): if isinstance(self.Leaf(), ct.Structure): raise IndexError("Leaf must be an integer type for default max functions") return self.sLeaf(max(self.getvalue(key))) def average(self, key): result = self.sum(key) return result.value / self.total_cpu class LruPerCpuHash(PerCpuHash): def __init__(self, *args, **kwargs): super(LruPerCpuHash, self).__init__(*args, **kwargs) class PerCpuArray(ArrayBase): def __init__(self, *args, **kwargs): self.reducer = kwargs.pop("reducer", None) super(PerCpuArray, self).__init__(*args, **kwargs) self.sLeaf = self.Leaf self.total_cpu = len(get_possible_cpus()) # This needs to be 8 as hard coded into the linux kernel. self.alignment = ct.sizeof(self.sLeaf) % 8 if self.alignment == 0: self.Leaf = self.sLeaf * self.total_cpu else: # Currently Float, Char, un-aligned structs are not supported if self.sLeaf == ct.c_uint: self.Leaf = ct.c_uint64 * self.total_cpu elif self.sLeaf == ct.c_int: self.Leaf = ct.c_int64 * self.total_cpu else: raise IndexError("Leaf must be aligned to 8 bytes") def getvalue(self, key): result = super(PerCpuArray, self).__getitem__(key) if self.alignment == 0: ret = result else: ret = (self.sLeaf * self.total_cpu)() for i in range(0, self.total_cpu): ret[i] = result[i] return ret def __getitem__(self, key): if (self.reducer): return reduce(self.reducer, self.getvalue(key)) else: return self.getvalue(key) def __setitem__(self, key, leaf): super(PerCpuArray, self).__setitem__(key, leaf) def __delitem__(self, key): # Delete in this type does not have an effect, so zero out instead self.clearitem(key) def sum(self, key): if isinstance(self.Leaf(), ct.Structure): raise IndexError("Leaf must be an integer type for default sum functions") return self.sLeaf(sum(self.getvalue(key))) def max(self, key): if isinstance(self.Leaf(), ct.Structure): raise IndexError("Leaf must be an integer type for default max functions") return self.sLeaf(max(self.getvalue(key))) def average(self, key): result = self.sum(key) return result.value / self.total_cpu class LpmTrie(TableBase): def __init__(self, *args, **kwargs): super(LpmTrie, self).__init__(*args, **kwargs) def __len__(self): raise NotImplementedError class StackTrace(TableBase): MAX_DEPTH = 127 BPF_F_STACK_BUILD_ID = (1<<5) BPF_STACK_BUILD_ID_EMPTY = 0 #can't get stacktrace BPF_STACK_BUILD_ID_VALID = 1 #valid build-id,ip BPF_STACK_BUILD_ID_IP = 2 #fallback to ip def __init__(self, *args, **kwargs): super(StackTrace, self).__init__(*args, **kwargs) class StackWalker(object): def __init__(self, stack, flags, resolve=None): self.stack = stack self.n = -1 self.resolve = resolve self.flags = flags def __iter__(self): return self def __next__(self): return self.next() def next(self): self.n += 1 if self.n == StackTrace.MAX_DEPTH: raise StopIteration() if self.flags & StackTrace.BPF_F_STACK_BUILD_ID: addr = self.stack.trace[self.n] if addr.status == StackTrace.BPF_STACK_BUILD_ID_IP or \ addr.status == StackTrace.BPF_STACK_BUILD_ID_EMPTY: raise StopIteration() else: addr = self.stack.ip[self.n] if addr == 0 : raise StopIteration() return self.resolve(addr) if self.resolve else addr def walk(self, stack_id, resolve=None): return StackTrace.StackWalker(self[self.Key(stack_id)], self.flags, resolve) def __len__(self): i = 0 for k in self: i += 1 return i def clear(self): pass class DevMap(ArrayBase): def __init__(self, *args, **kwargs): super(DevMap, self).__init__(*args, **kwargs) class CpuMap(ArrayBase): def __init__(self, *args, **kwargs): super(CpuMap, self).__init__(*args, **kwargs) class XskMap(ArrayBase): def __init__(self, *args, **kwargs): super(XskMap, self).__init__(*args, **kwargs) class MapInMapArray(ArrayBase): def __init__(self, *args, **kwargs): super(MapInMapArray, self).__init__(*args, **kwargs) class MapInMapHash(HashTable): def __init__(self, *args, **kwargs): super(MapInMapHash, self).__init__(*args, **kwargs) class RingBuf(TableBase): def __init__(self, *args, **kwargs): super(RingBuf, self).__init__(*args, **kwargs) self._ringbuf = None self._event_class = None def __delitem(self, key): pass def __del__(self): pass def __len__(self): return 0 def event(self, data): """event(data) When ring buffers are opened to receive custom event, the underlying event data struct which is defined in C in the BPF program can be deduced via this function. This avoids redundant definitions in Python. """ if self._event_class == None: self._event_class = _get_event_class(self) return ct.cast(data, ct.POINTER(self._event_class)).contents def open_ring_buffer(self, callback, ctx=None): """open_ring_buffer(callback) Opens a ring buffer to receive custom event data from the bpf program. The callback will be invoked for each event submitted from the kernel, up to millions per second. """ def ringbuf_cb_(ctx, data, size): try: ret = callback(ctx, data, size) # Callback for ringbufs should _always_ return an integer. # If the function the user registers does not, # simply fall back to returning 0. try: ret = int(ret) except: ret = 0 except IOError as e: if e.errno == errno.EPIPE: exit() else: raise e return ret fn = _RINGBUF_CB_TYPE(ringbuf_cb_) self.bpf._open_ring_buffer(self.map_fd, fn, ctx) # keep a refcnt self._cbs[0] = fn class QueueStack: # Flag for map.push BPF_EXIST = 2 def __init__(self, bpf, map_id, map_fd, leaftype): self.bpf = bpf self.map_id = map_id self.map_fd = map_fd self.Leaf = leaftype self.ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id) self.flags = lib.bpf_table_flags_id(self.bpf.module, self.map_id) self.max_entries = int(lib.bpf_table_max_entries_id(self.bpf.module, self.map_id)) def leaf_sprintf(self, leaf): buf = ct.create_string_buffer(ct.sizeof(self.Leaf) * 8) res = lib.bpf_table_leaf_snprintf(self.bpf.module, self.map_id, buf, len(buf), ct.byref(leaf)) if res < 0: raise Exception("Could not printf leaf") return buf.value def leaf_scanf(self, leaf_str): leaf = self.Leaf() res = lib.bpf_table_leaf_sscanf(self.bpf.module, self.map_id, leaf_str, ct.byref(leaf)) if res < 0: raise Exception("Could not scanf leaf") return leaf def push(self, leaf, flags=0): res = lib.bpf_update_elem(self.map_fd, None, ct.byref(leaf), flags) if res < 0: errstr = os.strerror(ct.get_errno()) raise Exception("Could not push to table: %s" % errstr) def pop(self): leaf = self.Leaf() res = lib.bpf_lookup_and_delete(self.map_fd, None, ct.byref(leaf)) if res < 0: raise KeyError("Could not pop from table") return leaf def peek(self): leaf = self.Leaf() res = lib.bpf_lookup_elem(self.map_fd, None, ct.byref(leaf)) if res < 0: raise KeyError("Could not peek table") return leaf def itervalues(self): # to avoid infinite loop, set maximum pops to max_entries cnt = self.max_entries while cnt: try: yield(self.pop()) cnt -= 1 except KeyError: return def values(self): return [value for value in self.itervalues()] disassembler.py000064400000050371152344707330007611 0ustar00# Copyright 2019 Clevernet # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from os import linesep import ctypes as ct from .table import get_table_type_name class OffsetUnion(ct.Union): _fields_ = [('offsetu', ct.c_uint16), ('offset', ct.c_int16)] class ImmUnion(ct.Union): _fields_ = [('immu', ct.c_uint32), ('imm', ct.c_int32)] class BPFInstrFields(ct.Structure): _pack_ = 1 _anonymous_ = ('o', 'i') _fields_ = [('opcode', ct.c_uint8), ('dst', ct.c_uint8, 4), ('src', ct.c_uint8, 4), ('o', OffsetUnion), ('i', ImmUnion)] class BPFInstr(ct.Union): _pack_ = 1 _anonymous_ = ('s') _fields_ = [('s', BPFInstrFields), ('instr', ct.c_uint64)] class BPFDecoder(): BPF_PSEUDO_CALL = 1 bpf_helpers = ['unspec', 'map_lookup_elem', 'map_update_elem', 'map_delete_elem', 'probe_read', 'ktime_get_ns', 'trace_printk', 'get_prandom_u32', 'get_smp_processor_id', 'skb_store_bytes', 'l3_csum_replace', 'l4_csum_replace', 'tail_call', 'clone_redirect', 'get_current_pid_tgid', 'get_current_uid_gid', 'get_current_comm', 'get_cgroup_classid', 'skb_vlan_push', 'skb_vlan_pop', 'skb_get_tunnel_key', 'skb_set_tunnel_key', 'perf_event_read', 'redirect', 'get_route_realm', 'perf_event_output', 'skb_load_bytes', 'get_stackid', 'csum_diff', 'skb_get_tunnel_opt', 'skb_set_tunnel_opt', 'skb_change_proto', 'skb_change_type', 'skb_under_cgroup', 'get_hash_recalc', 'get_current_task', 'probe_write_user', 'current_task_under_cgroup', 'skb_change_tail', 'skb_pull_data', 'csum_update', 'set_hash_invalid', 'get_numa_node_id', 'skb_change_head', 'xdp_adjust_head', 'probe_read_str', 'get_socket_cookie', 'get_socket_uid', 'set_hash', 'setsockopt', 'skb_adjust_room', 'redirect_map', 'sk_redirect_map', 'sock_map_update', 'xdp_adjust_meta', 'perf_event_read_value', 'perf_prog_read_value', 'getsockopt', 'override_return', 'sock_ops_cb_flags_set', 'msg_redirect_map', 'msg_apply_bytes', 'msg_cork_bytes', 'msg_pull_data', 'bind', 'xdp_adjust_tail', 'skb_get_xfrm_state', 'get_stack', 'skb_load_bytes_relative', 'fib_lookup', 'sock_hash_update', 'msg_redirect_hash', 'sk_redirect_hash', 'lwt_push_encap', 'lwt_seg6_store_bytes', 'lwt_seg6_adjust_srh', 'lwt_seg6_action', 'rc_repeat', 'rc_keydown', 'skb_cgroup_id', 'get_current_cgroup_id', 'get_local_storage', 'sk_select_reuseport', 'skb_ancestor_cgroup_id', 'sk_lookup_tcp', 'sk_lookup_udp', 'sk_release', 'map_push_elem', 'map_pop_elem', 'map_peek_elem', 'msg_push_data', 'msg_pop_data', 'rc_pointer_rel'] opcodes = {0x04: ('add32', 'dstimm', '+=', 32), 0x05: ('ja', 'joff', None, 64), 0x07: ('add', 'dstimm', '+=', 64), 0x0c: ('add32', 'dstsrc', '+=', 32), 0x0f: ('add', 'dstsrc', '+=', 64), 0x14: ('sub32', 'dstimm', '-=', 32), 0x15: ('jeq', 'jdstimmoff', '==', 64), 0x17: ('sub', 'dstimm', '-=', 64), 0x18: ('lddw', 'lddw', None, 64), 0x1c: ('sub32', 'dstsrc', '-=', 32), 0x1d: ('jeq', 'jdstsrcoff', '==', 64), 0x1f: ('sub', 'dstsrc', '-=', 64), 0x20: ('ldabsw', 'ldabs', None, 32), 0x24: ('mul32', 'dstimm', '*=', 32), 0x25: ('jgt', 'jdstimmoff', '>', 64), 0x27: ('mul', 'dstimm', '*=', 64), 0x28: ('ldabsh', 'ldabs', None, 16), 0x2c: ('mul32', 'dstsrc', '*=', 32), 0x2d: ('jgt', 'jdstsrcoff', '>', 64), 0x2f: ('mul', 'dstsrc', '*=', 64), 0x30: ('ldabsb', 'ldabs', None, 8), 0x34: ('div32', 'dstimm', '/=', 32), 0x35: ('jge', 'jdstimmoff', '>=', 64), 0x37: ('div', 'dstimm', '/=', 64), 0x38: ('ldabsdw', 'ldabs', None, 64), 0x3c: ('div32', 'dstsrc', '/=', 32), 0x3d: ('jge', 'jdstsrcoff', '>=', 64), 0x3f: ('div', 'dstsrc', '/=', 64), 0x40: ('ldindw', 'ldind', None, 32), 0x44: ('or32', 'dstimm_bw', '|=', 32), 0x45: ('jset', 'jdstimmoff', '&', 64), 0x47: ('or', 'dstimm_bw', '|=', 64), 0x48: ('ldindh', 'ldind', None, 16), 0x4c: ('or32', 'dstsrc', '|=', 32), 0x4d: ('jset', 'jdstsrcoff', '&', 64), 0x4f: ('or', 'dstsrc', '|=', 64), 0x50: ('ldindb', 'ldind', None, 8), 0x54: ('and32', 'dstimm_bw', '&=', 32), 0x55: ('jne', 'jdstimmoff', '!=', 64), 0x57: ('and', 'dstimm_bw', '&=', 64), 0x58: ('ldinddw', 'ldind', None, 64), 0x5c: ('and32', 'dstsrc', '&=', 32), 0x5d: ('jne', 'jdstsrcoff', '!=', 64), 0x5f: ('and', 'dstsrc', '&=', 64), 0x61: ('ldxw', 'ldstsrcoff', None, 32), 0x62: ('stw', 'sdstoffimm', None, 32), 0x63: ('stxw', 'sdstoffsrc', None, 32), 0x64: ('lsh32', 'dstimm', '<<=', 32), 0x65: ('jsgt', 'jdstimmoff', 's>', 64), 0x67: ('lsh', 'dstimm', '<<=', 64), 0x69: ('ldxh', 'ldstsrcoff', None, 16), 0x6a: ('sth', 'sdstoffimm', None, 16), 0x6b: ('stxh', 'sdstoffsrc', None, 16), 0x6c: ('lsh32', 'dstsrc', '<<=', 32), 0x6d: ('jsgt', 'jdstsrcoff', 's>', 64), 0x6f: ('lsh', 'dstsrc', '<<=', 64), 0x71: ('ldxb', 'ldstsrcoff', None, 8), 0x72: ('stb', 'sdstoffimm', None, 8), 0x73: ('stxb', 'sdstoffsrc', None, 8), 0x74: ('rsh32', 'dstimm', '>>=', 32), 0x75: ('jsge', 'jdstimmoff', 's>=', 64), 0x77: ('rsh', 'dstimm', '>>=', 64), 0x79: ('ldxdw', 'ldstsrcoff', None, 64), 0x7a: ('stdw', 'sdstoffimm', None, 64), 0x7b: ('stxdw', 'sdstoffsrc', None, 64), 0x7c: ('rsh32', 'dstsrc', '>>=', 32), 0x7d: ('jsge', 'jdstsrcoff', 's>=', 64), 0x7f: ('rsh', 'dstsrc', '>>=', 64), 0x84: ('neg32', 'dst', '~', 32), 0x85: ('call', 'call', None, 64), 0x87: ('neg', 'dst', '~', 64), 0x94: ('mod32', 'dstimm', '%=', 32), 0x95: ('exit', 'exit', None, 64), 0x97: ('mod', 'dstimm', '%=', 64), 0x9c: ('mod32', 'dstsrc', '%=', 32), 0x9f: ('mod', 'dstsrc', '%=', 64), 0xa4: ('xor32', 'dstimm_bw', '^=', 32), 0xa5: ('jlt', 'jdstimmoff', '<', 64), 0xa7: ('xor', 'dstimm_bw', '^=', 64), 0xac: ('xor32', 'dstsrc', '^=', 32), 0xad: ('jlt', 'jdstsrcoff', '<', 64), 0xaf: ('xor', 'dstsrc', '^=', 64), 0xb4: ('mov32', 'dstimm', '=', 32), 0xb5: ('jle', 'jdstimmoff', '<=', 64), 0xb7: ('mov', 'dstimm', '=', 64), 0xbc: ('mov32', 'dstsrc', '=', 32), 0xbd: ('jle', 'jdstsrcoff', '<=', 64), 0xbf: ('mov', 'dstsrc', '=', 64), 0xc4: ('arsh32', 'dstimm', 's>>=', 32), 0xc5: ('jslt', 'jdstimmoff', 's<', 64), 0xc7: ('arsh', 'dstimm', 's>>=', 64), 0xcc: ('arsh32', 'dstsrc', 's>>=', 32), 0xcd: ('jslt', 'jdstsrcoff', 's<', 64), 0xcf: ('arsh', 'dstsrc', 's>>=', 64), 0xd5: ('jsle', 'jdstimmoff', 's<=', 64), 0xdc: ('endian32', 'dstsrc', 'endian', 32), 0xdd: ('jsle', 'jdstimmoff', 's<=', 64),} @classmethod def decode(cls, i, w, w1): try: name, opclass, op, bits = cls.opcodes[w.opcode] if opclass == 'dstimm': return 'r%d %s %d' % (w.dst, op, w.imm), 0 elif opclass == 'dstimm_bw': return 'r%d %s 0x%x' % (w.dst, op, w.immu), 0 elif opclass == 'joff': return 'goto %s <%d>' % ('%+d' % (w.offset), i + w.offset + 1), 0 elif opclass == 'dstsrc': return 'r%d %s r%d' % (w.dst, op, w.src), 0 elif opclass == 'jdstimmoff': return 'if r%d %s %d goto pc%s <%d>' % (w.dst, op, w.imm, '%+d' % (w.offset), i + w.offset + 1), 0 elif opclass == 'jdstsrcoff': return 'if r%d %s r%d goto pc%s <%d>' % (w.dst, op, w.src, '%+d' % (w.offset), i + w.offset + 1), 0 elif opclass == 'lddw': # imm contains the file descriptor (FD) of the map being loaded; # the kernel will translate this into the proper address if w1 is None: raise Exception("lddw requires two instructions to be disassembled") if w1.imm == 0: return 'r%d = ' % (w.dst, w.imm), 1 imm = (w1.imm << 32) | w.imm return 'r%d = 0x%x' % (w.dst, imm), 1 elif opclass == 'ldabs': return 'r0 = *(u%s*)skb[%s]' % (bits, w.imm), 0 elif opclass == 'ldind': return 'r0 = *(u%d*)skb[r%d %s]' % (bits, w.src, '%+d' % (w.imm)), 0 elif opclass == 'ldstsrcoff': return 'r%d = *(u%d*)(r%d %s)' % (w.dst, bits, w.src, '%+d' % (w.offset)), 0 elif opclass == 'sdstoffimm': return '*(u%d*)(r%d %s) = %d' % (bits, w.dst, '%+d' % (w.offset), w.imm), 0 elif opclass == 'sdstoffsrc': return '*(u%d*)(r%d %s) = r%d' % (bits, w.dst, '%+d' % (w.offset), w.src), 0 elif opclass == 'dst': return 'r%d = %s (u%s)r%d' % (w.dst, op, bits, w.dst), 0 elif opclass == 'call': if w.src != cls.BPF_PSEUDO_CALL: try: return '%s bpf_%s#%d' % (name, cls.bpf_helpers[w.immu], w.immu), 0 except IndexError: return '%s ' % (op, w.immu), 0 return '%s %s' % (name, '%+d' % (w.imm)), 0 elif opclass == 'exit': return name, 0 else: raise Exception('unknown opcode class') except KeyError: return 'unknown <0x%x>' % (w.opcode) def disassemble_instruction(i, w0, w1=None): instr, skip = BPFDecoder.decode(i, w0, w1) return "%4d: (%02x) %s" % (i, w0.opcode, instr), skip def disassemble_str(bpfstr): ptr = ct.cast(ct.c_char_p(bpfstr), ct.POINTER(BPFInstr)) numinstr = int(len(bpfstr) / 8) w0 = ptr[0] skip = 0 instr_list = [] for i in range(1, numinstr): w1 = ptr[i] if skip: skip -= 1 instr_str = "%4d: (64-bit upper word)" % (i) else: instr_str, skip = disassemble_instruction(i - 1, w0, w1) instr_list.append(instr_str) w0 = w1 instr_str, skip = disassemble_instruction(numinstr - 1, w0, None) instr_list.append(instr_str) return instr_list def disassemble_prog(func_name, bpfstr): instr_list = ["Disassemble of BPF program %s:" % (func_name)] instr_list += disassemble_str(bpfstr) return linesep.join(instr_list) class MapDecoder (): ctype2str = {ct.c_bool: u"_Bool", ct.c_char: u"char", ct.c_wchar: u"wchar_t", ct.c_ubyte: u"unsigned char", ct.c_short: u"short", ct.c_ushort: u"unsigned short", ct.c_int: u"int", ct.c_uint: u"unsigned int", ct.c_long: u"long", ct.c_ulong: u"unsigned long", ct.c_longlong: u"long long", ct.c_ulonglong: u"unsigned long long", ct.c_float: u"float", ct.c_double: u"double", ct.c_longdouble: u"long double", ct.c_int64 * 2: u"__int128", ct.c_uint64 * 2: u"unsigned __int128",} @classmethod def get_ct_name(cls, t): try: if issubclass(t, ct.Structure): field_type_name = "struct" elif issubclass(t, ct.Union): field_type_name = "union" elif issubclass(t, ct.Array): field_type_name = cls.ctype2str[t._type_] + "[" + str(t._length_) + "]" else: field_type_name = cls.ctype2str[t] except KeyError: field_type_name = str(t) return field_type_name @classmethod def format_size_info(cls, offset, size, enabled=False, bitoffset=None): if not enabled: return "" if bitoffset is not None: return "[%d,%d +%d bit]" % (offset, bitoffset, size) return "[%d +%d] " % (offset, size) @classmethod def print_ct_map(cls, t, indent="", offset=0, sizeinfo=False): map_lines = [] try: for field_name, field_type in t._fields_: is_structured = (issubclass(field_type, ct.Structure) or issubclass(field_type, ct.Union)) field_type_name = cls.get_ct_name(field_type) field_offset = getattr(t, field_name).offset field_size = ct.sizeof(field_type) sizedesc = cls.format_size_info(offset + field_offset, field_size, sizeinfo) if is_structured: map_lines.append("%s%s%s {" % (indent, sizedesc, field_type_name)) map_lines += cls.print_ct_map(field_type, indent + " ", offset + field_offset) map_lines.append("%s} %s;" % (indent, field_name)) else: map_lines.append("%s%s%s %s;" % (indent, sizedesc, field_type_name, field_name)) except ValueError: # is a bit field offset_bits = 0 for field in t._fields_: if len(field) == 3: field_name, field_type, field_bits = field field_type_name = cls.get_ct_name(field_type) sizedesc = cls.format_size_info(offset, offset_bits, sizeinfo, field_bits) map_lines.append("%s%s%s %s:%d;" % (indent, sizedesc, field_type_name, field_name, field_bits)) else: # end of previous bit field field_name, field_type = field field_type_name = cls.get_ct_name(field_type) field_offset = getattr(t, field_name).offset field_size = ct.sizeof(field_type) field_bits = 0 offset_bits = 0 sizedesc = cls.format_size_info(offset + field_offset, field_size, sizeinfo) map_lines.append("%s%s%s %s;" % (indent, sizedesc, field_type_name, field_name)) offset += field_offset offset_bits += field_bits return map_lines @classmethod def print_map_ctype(cls, t, field_name, sizeinfo): is_structured = (issubclass(t, ct.Structure) or issubclass(t, ct.Union)) type_name = cls.get_ct_name(t) if is_structured: map_lines = [" %s {" % (type_name)] map_lines += cls.print_ct_map(t, " ", sizeinfo=sizeinfo) map_lines.append(" } %s;" % (field_name)) else: map_lines = [" %s %s;" % (type_name, field_name)] return map_lines @classmethod def decode_map(cls, map_name, map_obj, map_type, sizeinfo=False): map_lines = ['Layout of BPF map %s (type %s, FD %d, ID %d):' % (map_name, map_type, map_obj.map_fd, map_obj.map_id)] map_lines += cls.print_map_ctype(map_obj.Key, 'key', sizeinfo=sizeinfo) map_lines += cls.print_map_ctype(map_obj.Leaf, 'value', sizeinfo=sizeinfo) return linesep.join(map_lines) def decode_map(map_name, map_obj, map_type, sizeinfo=False): map_type_name = get_table_type_name(map_type) return MapDecoder.decode_map(map_name, map_obj, map_type_name, sizeinfo=sizeinfo) tcp.py000064400000003062152344707330005715 0ustar00# Copyright 2018 Netflix, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # from include/net/tcp_states.h: tcpstate = {} tcpstate[1] = 'ESTABLISHED' tcpstate[2] = 'SYN_SENT' tcpstate[3] = 'SYN_RECV' tcpstate[4] = 'FIN_WAIT1' tcpstate[5] = 'FIN_WAIT2' tcpstate[6] = 'TIME_WAIT' tcpstate[7] = 'CLOSE' tcpstate[8] = 'CLOSE_WAIT' tcpstate[9] = 'LAST_ACK' tcpstate[10] = 'LISTEN' tcpstate[11] = 'CLOSING' tcpstate[12] = 'NEW_SYN_RECV' # from include/net/tcp.h: TCPHDR_FIN = 0x01 TCPHDR_SYN = 0x02 TCPHDR_RST = 0x04 TCPHDR_PSH = 0x08 TCPHDR_ACK = 0x10 TCPHDR_URG = 0x20 TCPHDR_ECE = 0x40 TCPHDR_CWR = 0x80 def flags2str(flags): arr = [] if flags & TCPHDR_FIN: arr.append("FIN") if flags & TCPHDR_SYN: arr.append("SYN") if flags & TCPHDR_RST: arr.append("RST") if flags & TCPHDR_PSH: arr.append("PSH") if flags & TCPHDR_ACK: arr.append("ACK") if flags & TCPHDR_URG: arr.append("URG") if flags & TCPHDR_ECE: arr.append("ECE") if flags & TCPHDR_CWR: arr.append("CWR") return "|".join(arr) version.py000064400000000027152344707330006612 0ustar00__version__ = '0.25.0' libbcc.py000064400000034341152344707330006351 0ustar00# Copyright 2015 PLUMgrid # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import ctypes as ct lib = ct.CDLL("libbcc.so.0", use_errno=True) # needed for perf_event_attr() ctype from .perf import Perf # keep in sync with bcc_common.h lib.bpf_module_create_c.restype = ct.c_void_p lib.bpf_module_create_c.argtypes = [ct.c_char_p, ct.c_uint, ct.POINTER(ct.c_char_p), ct.c_int, ct.c_bool, ct.c_char_p] lib.bpf_module_create_c_from_string.restype = ct.c_void_p lib.bpf_module_create_c_from_string.argtypes = [ct.c_char_p, ct.c_uint, ct.POINTER(ct.c_char_p), ct.c_int, ct.c_bool, ct.c_char_p] lib.bpf_module_rw_engine_enabled.restype = ct.c_bool lib.bpf_module_rw_engine_enabled.argtypes = None lib.bpf_module_destroy.restype = None lib.bpf_module_destroy.argtypes = [ct.c_void_p] lib.bpf_module_license.restype = ct.c_char_p lib.bpf_module_license.argtypes = [ct.c_void_p] lib.bpf_module_kern_version.restype = ct.c_uint lib.bpf_module_kern_version.argtypes = [ct.c_void_p] lib.bpf_num_functions.restype = ct.c_ulonglong lib.bpf_num_functions.argtypes = [ct.c_void_p] lib.bpf_function_name.restype = ct.c_char_p lib.bpf_function_name.argtypes = [ct.c_void_p, ct.c_ulonglong] lib.bpf_function_start.restype = ct.c_void_p lib.bpf_function_start.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_function_size.restype = ct.c_size_t lib.bpf_function_size.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_id.restype = ct.c_ulonglong lib.bpf_table_id.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_fd.restype = ct.c_int lib.bpf_table_fd.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_type_id.restype = ct.c_int lib.bpf_table_type_id.argtypes = [ct.c_void_p, ct.c_ulonglong] lib.bpf_table_max_entries_id.restype = ct.c_ulonglong lib.bpf_table_max_entries_id.argtypes = [ct.c_void_p, ct.c_ulonglong] lib.bpf_table_flags_id.restype = ct.c_int lib.bpf_table_flags_id.argtypes = [ct.c_void_p, ct.c_ulonglong] lib.bpf_table_key_desc.restype = ct.c_char_p lib.bpf_table_key_desc.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_leaf_desc.restype = ct.c_char_p lib.bpf_table_leaf_desc.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_key_snprintf.restype = ct.c_int lib.bpf_table_key_snprintf.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.c_char_p, ct.c_ulonglong, ct.c_void_p] lib.bpf_table_leaf_snprintf.restype = ct.c_int lib.bpf_table_leaf_snprintf.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.c_char_p, ct.c_ulonglong, ct.c_void_p] lib.bpf_table_key_sscanf.restype = ct.c_int lib.bpf_table_key_sscanf.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.c_char_p, ct.c_void_p] lib.bpf_table_leaf_sscanf.restype = ct.c_int lib.bpf_table_leaf_sscanf.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.c_char_p, ct.c_void_p] lib.bpf_perf_event_fields.restype = ct.c_ulonglong lib.bpf_perf_event_fields.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_perf_event_field.restype = ct.c_char_p lib.bpf_perf_event_field.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_ulonglong] # keep in sync with libbpf.h lib.bpf_get_next_key.restype = ct.c_int lib.bpf_get_next_key.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p] lib.bpf_get_first_key.restype = ct.c_int lib.bpf_get_first_key.argtypes = [ct.c_int, ct.c_void_p, ct.c_uint] lib.bpf_lookup_elem.restype = ct.c_int lib.bpf_lookup_elem.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p] lib.bpf_update_elem.restype = ct.c_int lib.bpf_update_elem.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p, ct.c_ulonglong] lib.bpf_delete_elem.restype = ct.c_int lib.bpf_delete_elem.argtypes = [ct.c_int, ct.c_void_p] lib.bpf_delete_batch.restype = ct.c_int lib.bpf_delete_batch.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p] lib.bpf_update_batch.restype = ct.c_int lib.bpf_update_batch.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p, ct.POINTER(ct.c_uint32)] lib.bpf_lookup_batch.restype = ct.c_int lib.bpf_lookup_batch.argtypes = [ct.c_int, ct.POINTER(ct.c_uint32), ct.POINTER(ct.c_uint32), ct.c_void_p, ct.c_void_p, ct.c_void_p] lib.bpf_lookup_and_delete_batch.restype = ct.c_int lib.bpf_lookup_and_delete_batch.argtypes = [ct.c_int, ct.POINTER(ct.c_uint32), ct.POINTER(ct.c_uint32), ct.c_void_p, ct.c_void_p, ct.c_void_p] lib.bpf_open_raw_sock.restype = ct.c_int lib.bpf_open_raw_sock.argtypes = [ct.c_char_p] lib.bpf_attach_socket.restype = ct.c_int lib.bpf_attach_socket.argtypes = [ct.c_int, ct.c_int] lib.bcc_func_load.restype = ct.c_int lib.bcc_func_load.argtypes = [ct.c_void_p, ct.c_int, ct.c_char_p, ct.c_void_p, ct.c_size_t, ct.c_char_p, ct.c_uint, ct.c_int, ct.c_char_p, ct.c_uint, ct.c_char_p, ct.c_uint] _RAW_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_void_p, ct.c_int) _LOST_CB_TYPE = ct.CFUNCTYPE(None, ct.py_object, ct.c_ulonglong) lib.bpf_attach_kprobe.restype = ct.c_int lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, ct.c_ulonglong, ct.c_int] lib.bpf_detach_kprobe.restype = ct.c_int lib.bpf_detach_kprobe.argtypes = [ct.c_char_p] lib.bpf_attach_uprobe.restype = ct.c_int lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, ct.c_ulonglong, ct.c_int] lib.bpf_detach_uprobe.restype = ct.c_int lib.bpf_detach_uprobe.argtypes = [ct.c_char_p] lib.bpf_attach_tracepoint.restype = ct.c_int lib.bpf_attach_tracepoint.argtypes = [ct.c_int, ct.c_char_p, ct.c_char_p] lib.bpf_detach_tracepoint.restype = ct.c_int lib.bpf_detach_tracepoint.argtypes = [ct.c_char_p, ct.c_char_p] lib.bpf_attach_raw_tracepoint.restype = ct.c_int lib.bpf_attach_raw_tracepoint.argtypes = [ct.c_int, ct.c_char_p] lib.bpf_attach_kfunc.restype = ct.c_int lib.bpf_attach_kfunc.argtypes = [ct.c_int] lib.bpf_attach_lsm.restype = ct.c_int lib.bpf_attach_lsm.argtypes = [ct.c_int] lib.bpf_prog_attach.restype = ct.c_int lib.bpf_prog_attach.argtype = [ct.c_int, ct.c_int, ct.c_int, ct.c_uint] lib.bpf_prog_detach2.restype = ct.c_int lib.bpf_prog_detach2.argtype = [ct.c_int, ct.c_int, ct.c_int] lib.bpf_has_kernel_btf.restype = ct.c_bool lib.bpf_has_kernel_btf.argtypes = None lib.kernel_struct_has_field.restype = ct.c_int lib.kernel_struct_has_field.argtypes = [ct.c_char_p, ct.c_char_p] lib.bpf_open_perf_buffer.restype = ct.c_void_p lib.bpf_open_perf_buffer.argtypes = [_RAW_CB_TYPE, _LOST_CB_TYPE, ct.py_object, ct.c_int, ct.c_int, ct.c_int] class bcc_perf_buffer_opts(ct.Structure): _fields_ = [ ('pid', ct.c_int), ('cpu', ct.c_int), ('wakeup_events', ct.c_int), ] lib.bpf_open_perf_buffer_opts.restype = ct.c_void_p lib.bpf_open_perf_buffer_opts.argtypes = [_RAW_CB_TYPE, _LOST_CB_TYPE, ct.py_object, ct.c_int, ct.POINTER(bcc_perf_buffer_opts)] lib.bpf_open_perf_event.restype = ct.c_int lib.bpf_open_perf_event.argtypes = [ct.c_uint, ct.c_ulonglong, ct.c_int, ct.c_int] lib.perf_reader_poll.restype = ct.c_int lib.perf_reader_poll.argtypes = [ct.c_int, ct.POINTER(ct.c_void_p), ct.c_int] lib.perf_reader_consume.restype = ct.c_int lib.perf_reader_consume.argtypes = [ct.c_int, ct.POINTER(ct.c_void_p)] lib.perf_reader_free.restype = None lib.perf_reader_free.argtypes = [ct.c_void_p] lib.perf_reader_fd.restype = int lib.perf_reader_fd.argtypes = [ct.c_void_p] lib.bpf_attach_xdp.restype = ct.c_int lib.bpf_attach_xdp.argtypes = [ct.c_char_p, ct.c_int, ct.c_uint] lib.bpf_attach_perf_event.restype = ct.c_int lib.bpf_attach_perf_event.argtype = [ct.c_int, ct.c_uint, ct.c_uint, ct.c_ulonglong, ct.c_ulonglong, ct.c_int, ct.c_int, ct.c_int] lib.bpf_attach_perf_event_raw.restype = ct.c_int lib.bpf_attach_perf_event_raw.argtype = [Perf.perf_event_attr(), ct.c_uint, ct.c_uint, ct.c_uint, ct.c_uint] lib.bpf_close_perf_event_fd.restype = ct.c_int lib.bpf_close_perf_event_fd.argtype = [ct.c_int] _RINGBUF_CB_TYPE = ct.CFUNCTYPE(ct.c_int, ct.c_void_p, ct.c_void_p, ct.c_int) lib.bpf_new_ringbuf.restype = ct.c_void_p lib.bpf_new_ringbuf.argtypes = [ct.c_int, _RINGBUF_CB_TYPE, ct.c_void_p] lib.bpf_free_ringbuf.restype = None lib.bpf_free_ringbuf.argtypes = [ct.c_void_p] lib.bpf_add_ringbuf.restype = ct.c_int lib.bpf_add_ringbuf.argtypes = [ct.c_void_p, ct.c_int, _RINGBUF_CB_TYPE, ct.c_void_p] lib.bpf_poll_ringbuf.restype = ct.c_int lib.bpf_poll_ringbuf.argtypes = [ct.c_void_p, ct.c_int] lib.bpf_consume_ringbuf.restype = ct.c_int lib.bpf_consume_ringbuf.argtypes = [ct.c_void_p] # bcc symbol helpers class bcc_symbol(ct.Structure): _fields_ = [ ('name', ct.c_char_p), ('demangle_name', ct.c_char_p), ('module', ct.POINTER(ct.c_char)), ('offset', ct.c_ulonglong), ] class bcc_ip_offset_union(ct.Union): _fields_ = [ ('offset', ct.c_uint64), ('ip', ct.c_uint64) ] class bcc_stacktrace_build_id(ct.Structure): _fields_ = [ ('status', ct.c_uint32), ('build_id',ct.c_ubyte*20), ('u',bcc_ip_offset_union) ] class bcc_symbol_option(ct.Structure): _fields_ = [ ('use_debug_file', ct.c_int), ('check_debug_file_crc', ct.c_int), ('lazy_symbolize', ct.c_int), ('use_symbol_type', ct.c_uint), ] lib.bcc_procutils_which_so.restype = ct.POINTER(ct.c_char) lib.bcc_procutils_which_so.argtypes = [ct.c_char_p, ct.c_int] lib.bcc_procutils_free.restype = None lib.bcc_procutils_free.argtypes = [ct.c_void_p] lib.bcc_procutils_language.restype = ct.POINTER(ct.c_char) lib.bcc_procutils_language.argtypes = [ct.c_int] lib.bcc_resolve_symname.restype = ct.c_int lib.bcc_resolve_symname.argtypes = [ ct.c_char_p, ct.c_char_p, ct.c_ulonglong, ct.c_int, ct.POINTER(bcc_symbol_option), ct.POINTER(bcc_symbol)] _SYM_CB_TYPE = ct.CFUNCTYPE(ct.c_int, ct.c_char_p, ct.c_ulonglong) lib.bcc_foreach_function_symbol.restype = ct.c_int lib.bcc_foreach_function_symbol.argtypes = [ct.c_char_p, _SYM_CB_TYPE] lib.bcc_symcache_new.restype = ct.c_void_p lib.bcc_symcache_new.argtypes = [ct.c_int, ct.POINTER(bcc_symbol_option)] lib.bcc_free_symcache.restype = ct.c_void_p lib.bcc_free_symcache.argtypes = [ct.c_void_p, ct.c_int] lib.bcc_buildsymcache_new.restype = ct.c_void_p lib.bcc_buildsymcache_new.argtypes = None lib.bcc_free_buildsymcache.restype = None lib.bcc_free_buildsymcache.argtypes = [ct.c_void_p] lib.bcc_buildsymcache_add_module.restype = ct.c_int lib.bcc_buildsymcache_add_module.argtypes = [ct.c_void_p, ct.c_char_p] lib.bcc_buildsymcache_resolve.restype = ct.c_int lib.bcc_buildsymcache_resolve.argtypes = [ct.c_void_p, ct.POINTER(bcc_stacktrace_build_id), ct.POINTER(bcc_symbol)] lib.bcc_symbol_free_demangle_name.restype = ct.c_void_p lib.bcc_symbol_free_demangle_name.argtypes = [ct.POINTER(bcc_symbol)] lib.bcc_symcache_resolve.restype = ct.c_int lib.bcc_symcache_resolve.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.POINTER(bcc_symbol)] lib.bcc_symcache_resolve_no_demangle.restype = ct.c_int lib.bcc_symcache_resolve_no_demangle.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.POINTER(bcc_symbol)] lib.bcc_symcache_resolve_name.restype = ct.c_int lib.bcc_symcache_resolve_name.argtypes = [ ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.POINTER(ct.c_ulonglong)] lib.bcc_symcache_refresh.restype = None lib.bcc_symcache_refresh.argtypes = [ct.c_void_p] lib.bcc_free_memory.restype = ct.c_int lib.bcc_free_memory.argtypes = None lib.bcc_usdt_new_frompid.restype = ct.c_void_p lib.bcc_usdt_new_frompid.argtypes = [ct.c_int, ct.c_char_p] lib.bcc_usdt_new_frompath.restype = ct.c_void_p lib.bcc_usdt_new_frompath.argtypes = [ct.c_char_p] lib.bcc_usdt_close.restype = None lib.bcc_usdt_close.argtypes = [ct.c_void_p] lib.bcc_usdt_enable_probe.restype = ct.c_int lib.bcc_usdt_enable_probe.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p] lib.bcc_usdt_enable_fully_specified_probe.restype = ct.c_int lib.bcc_usdt_enable_fully_specified_probe.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_char_p] lib.bcc_usdt_genargs.restype = ct.c_char_p lib.bcc_usdt_genargs.argtypes = [ct.POINTER(ct.c_void_p), ct.c_int] lib.bcc_usdt_get_probe_argctype.restype = ct.c_char_p lib.bcc_usdt_get_probe_argctype.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_int] lib.bcc_usdt_get_fully_specified_probe_argctype.restype = ct.c_char_p lib.bcc_usdt_get_fully_specified_probe_argctype.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_int] class bcc_usdt(ct.Structure): _fields_ = [ ('provider', ct.c_char_p), ('name', ct.c_char_p), ('bin_path', ct.c_char_p), ('semaphore', ct.c_ulonglong), ('num_locations', ct.c_int), ('num_arguments', ct.c_int), ] class bcc_usdt_location(ct.Structure): _fields_ = [ ('address', ct.c_ulonglong), ('bin_path', ct.c_char_p), ] class BCC_USDT_ARGUMENT_FLAGS(object): NONE = 0x0 CONSTANT = 0x1 DEREF_OFFSET = 0x2 DEREF_IDENT = 0x4 BASE_REGISTER_NAME = 0x8 INDEX_REGISTER_NAME = 0x10 SCALE = 0x20 class bcc_usdt_argument(ct.Structure): _fields_ = [ ('size', ct.c_int), ('valid', ct.c_int), ('constant', ct.c_longlong), ('deref_offset', ct.c_int), ('deref_ident', ct.c_char_p), ('base_register_name', ct.c_char_p), ('index_register_name', ct.c_char_p), ('scale', ct.c_int) ] _USDT_CB = ct.CFUNCTYPE(None, ct.POINTER(bcc_usdt)) lib.bcc_usdt_foreach.restype = None lib.bcc_usdt_foreach.argtypes = [ct.c_void_p, _USDT_CB] lib.bcc_usdt_get_location.restype = ct.c_int lib.bcc_usdt_get_location.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_int, ct.POINTER(bcc_usdt_location)] lib.bcc_usdt_get_argument.restype = ct.c_int lib.bcc_usdt_get_argument.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_int, ct.c_int, ct.POINTER(bcc_usdt_argument)] _USDT_PROBE_CB = ct.CFUNCTYPE(None, ct.c_char_p, ct.c_char_p, ct.c_ulonglong, ct.c_int) lib.bcc_usdt_foreach_uprobe.restype = None lib.bcc_usdt_foreach_uprobe.argtypes = [ct.c_void_p, _USDT_PROBE_CB] containers.py000064400000007153152344707330007301 0ustar00# Copyright 2020 Kinvolk GmbH # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. def _cgroup_filter_func_writer(cgroupmap): if not cgroupmap: return """ static inline int _cgroup_filter() { return 0; } """ text = """ BPF_TABLE_PINNED("hash", u64, u64, cgroupset, 1024, "CGROUP_PATH"); static inline int _cgroup_filter() { u64 cgroupid = bpf_get_current_cgroup_id(); return cgroupset.lookup(&cgroupid) == NULL; } """ return text.replace('CGROUP_PATH', cgroupmap) def _mntns_filter_func_writer(mntnsmap): if not mntnsmap: return """ static inline int _mntns_filter() { return 0; } """ text = """ #include #include #include /* see mountsnoop.py: * XXX: struct mnt_namespace is defined in fs/mount.h, which is private * to the VFS and not installed in any kernel-devel packages. So, let's * duplicate the important part of the definition. There are actually * more members in the real struct, but we don't need them, and they're * more likely to change. */ struct mnt_namespace { // This field was removed in https://github.com/torvalds/linux/commit/1a7b8969e664d6af328f00fe6eb7aabd61a71d13 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0) atomic_t count; #endif struct ns_common ns; }; /* * To add mountsnoop support for --selector option, we need to call * filter_by_containers(). * This function adds code which defines struct mnt_namespace. * The problem is that this struct is also defined in mountsnoop BPF code. * To avoid redefining it in mountnsoop code, we define * MNT_NAMESPACE_DEFINED here. * Then, in mountsnoop code, the struct mnt_namespace definition is guarded * by: * #ifndef MNT_NAMESPACE_DEFINED * // ... * #endif */ #define MNT_NAMESPACE_DEFINED BPF_TABLE_PINNED("hash", u64, u32, mount_ns_set, 1024, "MOUNT_NS_PATH"); static inline int _mntns_filter() { struct task_struct *current_task; struct nsproxy *nsproxy; struct mnt_namespace *mnt_ns; unsigned int inum; u64 ns_id; current_task = (struct task_struct *)bpf_get_current_task(); if (bpf_probe_read_kernel(&nsproxy, sizeof(nsproxy), ¤t_task->nsproxy)) return 0; if (bpf_probe_read_kernel(&mnt_ns, sizeof(mnt_ns), &nsproxy->mnt_ns)) return 0; if (bpf_probe_read_kernel(&inum, sizeof(inum), &mnt_ns->ns.inum)) return 0; ns_id = (u64) inum; return mount_ns_set.lookup(&ns_id) == NULL; } """ return text.replace('MOUNT_NS_PATH', mntnsmap) def filter_by_containers(args): filter_by_containers_text = """ static inline int container_should_be_filtered() { return _cgroup_filter() || _mntns_filter(); } """ cgroupmap_text = _cgroup_filter_func_writer(args.cgroupmap) mntnsmap_text = _mntns_filter_func_writer(args.mntnsmap) return cgroupmap_text + mntnsmap_text + filter_by_containers_text usdt.py000064400000022065152344707330006112 0ustar00# Copyright 2016 Sasha Goldshtein # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import ctypes as ct import sys from .libbcc import lib, _USDT_CB, _USDT_PROBE_CB, \ bcc_usdt_location, bcc_usdt_argument, \ BCC_USDT_ARGUMENT_FLAGS class USDTException(Exception): pass class USDTProbeArgument(object): def __init__(self, argument): self.signed = argument.size < 0 self.size = abs(argument.size) self.valid = argument.valid if self.valid & BCC_USDT_ARGUMENT_FLAGS.CONSTANT != 0: self.constant = argument.constant if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0: self.deref_offset = argument.deref_offset if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT != 0: self.deref_ident = argument.deref_ident if self.valid & BCC_USDT_ARGUMENT_FLAGS.BASE_REGISTER_NAME != 0: self.base_register_name = argument.base_register_name if self.valid & BCC_USDT_ARGUMENT_FLAGS.INDEX_REGISTER_NAME != 0: self.index_register_name = argument.index_register_name if self.valid & BCC_USDT_ARGUMENT_FLAGS.SCALE != 0: self.scale = argument.scale def _size_prefix(self): return "%d %s bytes" % \ (self.size, "signed " if self.signed else "unsigned") def _format(self): # This mimics the logic in cc/usdt_args.cc that gives meaning to the # various argument settings. A change there will require a change here. if self.valid & BCC_USDT_ARGUMENT_FLAGS.CONSTANT != 0: return "%d" % self.constant if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET == 0: return "%s" % self.base_register_name.decode() if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0 and \ self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT == 0: if self.valid & BCC_USDT_ARGUMENT_FLAGS.INDEX_REGISTER_NAME != 0: index_offset = " + %s" % self.index_register_name.decode() if self.valid & BCC_USDT_ARGUMENT_FLAGS.SCALE != 0: index_offset += " * %d" % self.scale else: index_offset = "" sign = '+' if self.deref_offset >= 0 else '-' return "*(%s %s %d%s)" % (self.base_register_name.decode(), sign, abs(self.deref_offset), index_offset) if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0 and \ self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT != 0 and \ self.valid & BCC_USDT_ARGUMENT_FLAGS.BASE_REGISTER_NAME != 0 and \ self.base_register_name == "ip": sign = '+' if self.deref_offset >= 0 else '-' return "*(&%s %s %d)" % (self.deref_ident.decode(), sign, abs(self.deref_offset)) # If we got here, this is an unrecognized case. Doesn't mean it's # necessarily bad, so just provide the raw data. It just means that # other tools won't be able to work with this argument. return "unrecognized argument format, flags %d" % self.valid def __str__(self): return "%s @ %s" % (self._size_prefix(), self._format()) class USDTProbeLocation(object): def __init__(self, probe, index, location): self.probe = probe self.index = index self.num_arguments = probe.num_arguments self.address = location.address self.bin_path = location.bin_path def __str__(self): return "%s 0x%x" % (self.bin_path.decode(), self.address) def get_argument(self, index): arg = bcc_usdt_argument() res = lib.bcc_usdt_get_argument(self.probe.context, self.probe.provider, self.probe.name, self.index, index, ct.byref(arg)) if res != 0: raise USDTException( "error retrieving probe argument %d location %d" % (index, self.index)) return USDTProbeArgument(arg) class USDTProbe(object): def __init__(self, context, probe): self.context = context self.provider = probe.provider self.name = probe.name self.bin_path = probe.bin_path self.semaphore = probe.semaphore self.num_locations = probe.num_locations self.num_arguments = probe.num_arguments def __str__(self): return "%s:%s [sema 0x%x]" % \ (self.provider.decode(), self.name.decode(), self.semaphore) def short_name(self): return "%s:%s" % (self.provider.decode(), self.name.decode()) def get_location(self, index): loc = bcc_usdt_location() res = lib.bcc_usdt_get_location(self.context, self.provider, self.name, index, ct.byref(loc)) if res != 0: raise USDTException("error retrieving probe location %d" % index) return USDTProbeLocation(self, index, loc) class USDT(object): def __init__(self, pid=None, path=None): if pid and pid != -1: self.pid = pid if path: self.context = lib.bcc_usdt_new_frompid(pid, path.encode('ascii')) else: self.context = lib.bcc_usdt_new_frompid(pid, ct.c_char_p(0)) if self.context == None: raise USDTException("USDT failed to instrument PID %d" % pid) elif path: self.path = path self.context = lib.bcc_usdt_new_frompath(path.encode('ascii')) if self.context == None: raise USDTException("USDT failed to instrument path %s" % path) else: raise USDTException( "either a pid or a binary path must be specified") def __del__(self): lib.bcc_usdt_close(self.context) def enable_probe(self, probe, fn_name): probe_parts = probe.split(":", 1) if len(probe_parts) == 1: ret = lib.bcc_usdt_enable_probe( self.context, probe.encode('ascii'), fn_name.encode('ascii')) else: (provider_name, probe_name) = probe_parts ret = lib.bcc_usdt_enable_fully_specified_probe( self.context, provider_name.encode('ascii'), probe_name.encode('ascii'), fn_name.encode('ascii')) if ret != 0: raise USDTException( """Failed to enable USDT probe '%s': the specified pid might not contain the given language's runtime, or the runtime was not built with the required USDT probes. Look for a configure flag similar to --with-dtrace or --enable-dtrace. To check which probes are present in the process, use the tplist tool. """ % probe) def enable_probe_or_bail(self, probe, fn_name): try: self.enable_probe(probe, fn_name) except USDTException as e: print(e, file=sys.stderr) sys.exit(1) def get_context(self): return self.context def get_text(self): ctx_array = (ct.c_void_p * 1)() ctx_array[0] = ct.c_void_p(self.context) return lib.bcc_usdt_genargs(ctx_array, 1).decode() def get_probe_arg_ctype(self, probe_name, arg_index): probe_parts = probe_name.split(":", 1) if len(probe_parts) == 1: return lib.bcc_usdt_get_probe_argctype( self.context, probe_name.encode('ascii'), arg_index).decode() else: (provider_name, probe) = probe_parts return lib.bcc_usdt_get_fully_specified_probe_argctype( self.context, provider_name.encode('ascii'), probe.encode('ascii'), arg_index).decode() def enumerate_probes(self): probes = [] def _add_probe(probe): probes.append(USDTProbe(self.context, probe.contents)) lib.bcc_usdt_foreach(self.context, _USDT_CB(_add_probe)) return probes # This is called by the BPF module's __init__ when it realizes that there # is a USDT context and probes need to be attached. def attach_uprobes(self, bpf, attach_usdt_ignore_pid): probes = self.enumerate_active_probes() for (binpath, fn_name, addr, pid) in probes: if attach_usdt_ignore_pid: pid = -1 bpf.attach_uprobe(name=binpath.decode(), fn_name=fn_name.decode(), addr=addr, pid=pid) def enumerate_active_probes(self): probes = [] def _add_probe(binpath, fn_name, addr, pid): probes.append((binpath, fn_name, addr, pid)) lib.bcc_usdt_foreach_uprobe(self.context, _USDT_PROBE_CB(_add_probe)) return probes perf.py000064400000020204152344707330006060 0ustar00# Copyright 2016 Sasha Goldshtein # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import ctypes as ct import os from .utils import get_online_cpus class _sample_period_union(ct.Union): _fields_ = [ ('sample_period', ct.c_ulong), ('sample_freq', ct.c_ulong), ] class _wakeup_events_union(ct.Union): _fields_ = [ ('wakeup_events', ct.c_uint), ('wakeup_watermark', ct.c_uint), ] class _bp_addr_union(ct.Union): _fields_ = [ ('bp_addr', ct.c_ulong), ('kprobe_func', ct.c_ulong), ('uprobe_path', ct.c_ulong), ('config1', ct.c_ulong), ] class _bp_len_union(ct.Union): _fields_ = [ ('bp_len', ct.c_ulong), ('kprobe_addr', ct.c_ulong), ('probe_offset', ct.c_ulong), ('config2', ct.c_ulong), ] class Perf(object): class perf_event_attr(ct.Structure): _anonymous_ = [ "_sample_period_union", "_wakeup_events_union", "_bp_addr_union", "_bp_len_union" ] _fields_ = [ ('type', ct.c_uint), ('size', ct.c_uint), ('config', ct.c_ulong), ('_sample_period_union', _sample_period_union), # ct.c_ulong ('sample_type', ct.c_ulong), ('read_format', ct.c_ulong), ('disabled', ct.c_uint, 1), ('inherit', ct.c_uint, 1), ('pinned', ct.c_uint, 1), ('exclusive', ct.c_uint, 1), ('exclude_user', ct.c_uint, 1), ('exclude_kernel', ct.c_uint, 1), ('exclude_hv', ct.c_uint, 1), ('exclude_idle', ct.c_uint, 1), ('mmap', ct.c_uint, 1), ('comm', ct.c_uint, 1), ('freq', ct.c_uint, 1), ('inherit_stat', ct.c_uint, 1), ('enable_on_exec', ct.c_uint, 1), ('task', ct.c_uint, 1), ('watermark', ct.c_uint, 1), ('precise_ip', ct.c_uint, 2), ('mmap_data', ct.c_uint, 1), ('sample_id_all', ct.c_uint, 1), ('exclude_host', ct.c_uint, 1), ('exclude_guest', ct.c_uint, 1), ('exclude_callchain_kernel', ct.c_uint, 1), ('exclude_callchain_user', ct.c_uint, 1), ('mmap2', ct.c_uint, 1), ('comm_exec', ct.c_uint, 1), ('use_clockid', ct.c_uint, 1), ('context_switch', ct.c_uint, 1), ('write_backward', ct.c_uint, 1), ('namespaces', ct.c_uint, 1), ('ksymbol', ct.c_uint, 1), ('bpf_event', ct.c_uint, 1), ('aux_output', ct.c_uint, 1), ('cgroup', ct.c_uint, 1), ('text_poke', ct.c_uint, 1), ('__reserved_1', ct.c_uint, 30), ('_wakeup_events_union', _wakeup_events_union), # ct.c_uint ('bp_type', ct.c_uint), ('_bp_addr_union', _bp_addr_union), # ct.c_ulong ('_bp_len_union', _bp_len_union), # ct.c_ulong ('branch_sample_type', ct.c_ulong), ('sample_regs_user', ct.c_ulong), ('sample_stack_user', ct.c_uint), ('clockid', ct.c_int), ('sample_regs_intr', ct.c_ulong), ('aux_watermark', ct.c_uint), ('sample_max_stack', ct.c_uint16), ('__reserved_2', ct.c_uint16), ('aux_sample_size', ct.c_uint), ('__reserved_3', ct.c_uint), ] def __init__(self): self.size = 120 # PERF_ATTR_SIZE_VER6 self.ctype_fields = [item[0] for item in self._fields_] self.ctype_fields.extend([item[0] for item in _sample_period_union._fields_]) self.ctype_fields.extend([item[0] for item in _wakeup_events_union._fields_]) self.ctype_fields.extend([item[0] for item in _bp_addr_union._fields_]) self.ctype_fields.extend([item[0] for item in _bp_len_union._fields_]) def __setattr__(self, key, value): if hasattr(self, 'ctype_fields') and key not in self.ctype_fields: print("Warning: Setting field {} on perf_event_attr that isn't part of the ctype - {} won't make it to perf_event_open".format(key, key)) super(Perf.perf_event_attr, self).__setattr__(key, value) # x86 specific, from arch/x86/include/generated/uapi/asm/unistd_64.h NR_PERF_EVENT_OPEN = 298 # # Selected constants from include/uapi/linux/perf_event.h. # Values copied during Linux 4.7 series. # # perf_type_id PERF_TYPE_HARDWARE = 0 PERF_TYPE_SOFTWARE = 1 PERF_TYPE_TRACEPOINT = 2 PERF_TYPE_HW_CACHE = 3 # perf_event_sample_format PERF_SAMPLE_RAW = 1024 # it's a u32; could also try zero args # perf_event.h PERF_FLAG_FD_CLOEXEC = 8 PERF_EVENT_IOC_SET_FILTER = 1074275334 PERF_EVENT_IOC_ENABLE = 9216 # fetch syscall routines libc = ct.CDLL('libc.so.6', use_errno=True) syscall = libc.syscall # not declaring vararg types ioctl = libc.ioctl # not declaring vararg types @staticmethod def _open_for_cpu(cpu, attr): pfd = Perf.syscall(Perf.NR_PERF_EVENT_OPEN, ct.byref(attr), attr.pid, cpu, -1, Perf.PERF_FLAG_FD_CLOEXEC) if pfd < 0: errno_ = ct.get_errno() raise OSError(errno_, os.strerror(errno_)) if attr.type == Perf.PERF_TYPE_TRACEPOINT: if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_SET_FILTER, "common_pid == -17") < 0: errno_ = ct.get_errno() raise OSError(errno_, os.strerror(errno_)) # we don't setup the perf ring buffers, as we won't read them if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_ENABLE, 0) < 0: errno_ = ct.get_errno() raise OSError(errno_, os.strerror(errno_)) @staticmethod def perf_event_open(tpoint_id, pid=-1, ptype=PERF_TYPE_TRACEPOINT, freq=0): attr = Perf.perf_event_attr() attr.config = tpoint_id attr.pid = pid attr.type = ptype attr.sample_type = Perf.PERF_SAMPLE_RAW if freq > 0: # setup sampling attr.freq = 1 # no mmap or comm attr.sample_period = freq else: attr.sample_period = 1 attr.wakeup_events = 9999999 # don't wake up for cpu in get_online_cpus(): Perf._open_for_cpu(cpu, attr) utils.py000064400000011433152344707330006270 0ustar00# Copyright 2016 Catalysts GmbH # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import ctypes as ct import sys import traceback import warnings import re from .libbcc import lib def _read_cpu_range(path): cpus = [] with open(path, 'r') as f: cpus_range_str = f.read() for cpu_range in cpus_range_str.split(','): rangeop = cpu_range.find('-') if rangeop == -1: cpus.append(int(cpu_range)) else: start = int(cpu_range[:rangeop]) end = int(cpu_range[rangeop+1:]) cpus.extend(range(start, end+1)) return cpus def get_online_cpus(): return _read_cpu_range('/sys/devices/system/cpu/online') def get_possible_cpus(): return _read_cpu_range('/sys/devices/system/cpu/possible') def detect_language(candidates, pid): res = lib.bcc_procutils_language(pid) language = ct.cast(res, ct.c_char_p).value.decode() return language if language in candidates else None FILESYSTEMENCODING = sys.getfilesystemencoding() def printb(s, file=sys.stdout, nl=1): """ printb(s) print a bytes object to stdout and flush """ buf = file.buffer if hasattr(file, "buffer") else file buf.write(s) if nl: buf.write(b"\n") file.flush() class ArgString(object): """ ArgString(arg) encapsulate a system argument that can be easily coerced to a bytes() object, which is better for comparing to kernel or probe data (which should never be en/decode()'ed). """ def __init__(self, arg): if sys.version_info[0] >= 3: self.s = arg else: self.s = arg.decode(FILESYSTEMENCODING) def __bytes__(self): return self.s.encode(FILESYSTEMENCODING) def __str__(self): return self.s def warn_with_traceback(message, category, filename, lineno, file=None, line=None): log = file if hasattr(file, "write") else sys.stderr traceback.print_stack(f=sys._getframe(2), file=log) log.write(warnings.formatwarning(message, category, filename, lineno, line)) # uncomment to get full tracebacks for invalid uses of python3+str in arguments #warnings.showwarning = warn_with_traceback _strict_bytes = False def _assert_is_bytes(arg): if arg is None: return arg if _strict_bytes: assert type(arg) is bytes, "not a bytes object: %r" % arg elif type(arg) is not bytes: warnings.warn("not a bytes object: %r" % arg, DeprecationWarning, 2) return ArgString(arg).__bytes__() return arg class StrcmpRewrite(object): @staticmethod def _generate_streq_function(string, probe_read_func, streq_functions, probeid): fname = "streq_%d" % probeid streq_functions += """ static inline bool %s(char const *ignored, uintptr_t str) { char needle[] = %s; char haystack[sizeof(needle)]; %s(&haystack, sizeof(haystack), (void *)str); for (int i = 0; i < sizeof(needle) - 1; ++i) { if (needle[i] != haystack[i]) { return false; } } return true; } """ % (fname, string, probe_read_func) return fname, streq_functions @staticmethod def rewrite_expr(expr, bin_cmp, is_user, probe_user_list, streq_functions, probeid): if bin_cmp: STRCMP_RE = 'STRCMP\\(\"([^"]+)\\",(.+?)\\)' else: STRCMP_RE = 'STRCMP\\(("[^"]+\\"),(.+?)\\)' matches = re.finditer(STRCMP_RE, expr) for match in matches: string = match.group(1) probe_read_func = "bpf_probe_read" # if user probe or @user tag is specified, use # bpf_probe_read_user for char* read if is_user or \ match.group(2).strip() in probe_user_list: probe_read_func = "bpf_probe_read_user" fname, streq_functions = StrcmpRewrite._generate_streq_function( string, probe_read_func, streq_functions, probeid) probeid += 1 expr = expr.replace("STRCMP", fname, 1) rdict = { "expr": expr, "streq_functions": streq_functions, "probeid": probeid } return rdict __init__.py000064400000204150152344707330006667 0ustar00# Copyright 2015 PLUMgrid # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import atexit import ctypes as ct import fcntl import json import os import re import errno import sys import platform from .libbcc import lib, bcc_symbol, bcc_symbol_option, bcc_stacktrace_build_id, _SYM_CB_TYPE from .table import Table, PerfEventArray, RingBuf, BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK from .perf import Perf from .utils import get_online_cpus, printb, _assert_is_bytes, ArgString, StrcmpRewrite from .version import __version__ from .disassembler import disassemble_prog, decode_map from .usdt import USDT, USDTException try: basestring except NameError: # Python 3 basestring = str _default_probe_limit = 1000 _num_open_probes = 0 # for tests def _get_num_open_probes(): global _num_open_probes return _num_open_probes TRACEFS = "/sys/kernel/debug/tracing" # Debug flags # Debug output compiled LLVM IR. DEBUG_LLVM_IR = 0x1 # Debug output loaded BPF bytecode and register state on branches. DEBUG_BPF = 0x2 # Debug output pre-processor result. DEBUG_PREPROCESSOR = 0x4 # Debug output ASM instructions embedded with source. DEBUG_SOURCE = 0x8 # Debug output register state on all instructions in addition to DEBUG_BPF. DEBUG_BPF_REGISTER_STATE = 0x10 # Debug BTF. DEBUG_BTF = 0x20 class SymbolCache(object): def __init__(self, pid): self.cache = lib.bcc_symcache_new( pid, ct.cast(None, ct.POINTER(bcc_symbol_option))) def resolve(self, addr, demangle): """ Return a tuple of the symbol (function), its offset from the beginning of the function, and the module in which it lies. For example: ("start_thread", 0x202, "/usr/lib/.../libpthread-2.24.so") If the symbol cannot be found but we know which module it is in, return the module name and the offset from the beginning of the module. If we don't even know the module, return the absolute address as the offset. """ sym = bcc_symbol() if demangle: res = lib.bcc_symcache_resolve(self.cache, addr, ct.byref(sym)) else: res = lib.bcc_symcache_resolve_no_demangle(self.cache, addr, ct.byref(sym)) if res < 0: if sym.module and sym.offset: return (None, sym.offset, ct.cast(sym.module, ct.c_char_p).value) return (None, addr, None) if demangle: name_res = sym.demangle_name lib.bcc_symbol_free_demangle_name(ct.byref(sym)) else: name_res = sym.name return (name_res, sym.offset, ct.cast(sym.module, ct.c_char_p).value) def resolve_name(self, module, name): module = _assert_is_bytes(module) name = _assert_is_bytes(name) addr = ct.c_ulonglong() if lib.bcc_symcache_resolve_name(self.cache, module, name, ct.byref(addr)) < 0: return -1 return addr.value class PerfType: # From perf_type_id in uapi/linux/perf_event.h HARDWARE = 0 SOFTWARE = 1 TRACEPOINT = 2 HW_CACHE = 3 RAW = 4 BREAKPOINT = 5 class PerfHWConfig: # From perf_hw_id in uapi/linux/perf_event.h CPU_CYCLES = 0 INSTRUCTIONS = 1 CACHE_REFERENCES = 2 CACHE_MISSES = 3 BRANCH_INSTRUCTIONS = 4 BRANCH_MISSES = 5 BUS_CYCLES = 6 STALLED_CYCLES_FRONTEND = 7 STALLED_CYCLES_BACKEND = 8 REF_CPU_CYCLES = 9 class PerfSWConfig: # From perf_sw_id in uapi/linux/perf_event.h CPU_CLOCK = 0 TASK_CLOCK = 1 PAGE_FAULTS = 2 CONTEXT_SWITCHES = 3 CPU_MIGRATIONS = 4 PAGE_FAULTS_MIN = 5 PAGE_FAULTS_MAJ = 6 ALIGNMENT_FAULTS = 7 EMULATION_FAULTS = 8 DUMMY = 9 BPF_OUTPUT = 10 class PerfEventSampleFormat: # from perf_event_sample_format in uapi/linux/bpf.h IP = (1 << 0) TID = (1 << 1) TIME = (1 << 2) ADDR = (1 << 3) READ = (1 << 4) CALLCHAIN = (1 << 5) ID = (1 << 6) CPU = (1 << 7) PERIOD = (1 << 8) STREAM_ID = (1 << 9) RAW = (1 << 10) BRANCH_STACK = (1 << 11) REGS_USER = (1 << 12) STACK_USER = (1 << 13) WEIGHT = (1 << 14) DATA_SRC = (1 << 15) IDENTIFIER = (1 << 16) TRANSACTION = (1 << 17) REGS_INTR = (1 << 18) PHYS_ADDR = (1 << 19) AUX = (1 << 20) CGROUP = (1 << 21) DATA_PAGE_SIZE = (1 << 22) CODE_PAGE_SIZE = (1 << 23) WEIGHT_STRUCT = (1 << 24) class BPFProgType: # From bpf_prog_type in uapi/linux/bpf.h SOCKET_FILTER = 1 KPROBE = 2 SCHED_CLS = 3 SCHED_ACT = 4 TRACEPOINT = 5 XDP = 6 PERF_EVENT = 7 CGROUP_SKB = 8 CGROUP_SOCK = 9 LWT_IN = 10 LWT_OUT = 11 LWT_XMIT = 12 SOCK_OPS = 13 SK_SKB = 14 CGROUP_DEVICE = 15 SK_MSG = 16 RAW_TRACEPOINT = 17 CGROUP_SOCK_ADDR = 18 CGROUP_SOCKOPT = 25 TRACING = 26 LSM = 29 class BPFAttachType: # from bpf_attach_type uapi/linux/bpf.h CGROUP_INET_INGRESS = 0 CGROUP_INET_EGRESS = 1 CGROUP_INET_SOCK_CREATE = 2 CGROUP_SOCK_OPS = 3 SK_SKB_STREAM_PARSER = 4 SK_SKB_STREAM_VERDICT = 5 CGROUP_DEVICE = 6 SK_MSG_VERDICT = 7 CGROUP_INET4_BIND = 8 CGROUP_INET6_BIND = 9 CGROUP_INET4_CONNECT = 10 CGROUP_INET6_CONNECT = 11 CGROUP_INET4_POST_BIND = 12 CGROUP_INET6_POST_BIND = 13 CGROUP_UDP4_SENDMSG = 14 CGROUP_UDP6_SENDMSG = 15 LIRC_MODE2 = 16 FLOW_DISSECTOR = 17 CGROUP_SYSCTL = 18 CGROUP_UDP4_RECVMSG = 19 CGROUP_UDP6_RECVMSG = 20 CGROUP_GETSOCKOPT = 21 CGROUP_SETSOCKOPT = 22 TRACE_RAW_TP = 23 TRACE_FENTRY = 24 TRACE_FEXIT = 25 MODIFY_RETURN = 26 LSM_MAC = 27 TRACE_ITER = 28 CGROUP_INET4_GETPEERNAME = 29 CGROUP_INET6_GETPEERNAME = 30 CGROUP_INET4_GETSOCKNAME = 31 CGROUP_INET6_GETSOCKNAME = 32 XDP_DEVMAP = 33 CGROUP_INET_SOCK_RELEASE = 34 XDP_CPUMAP = 35 SK_LOOKUP = 36 XDP = 37 SK_SKB_VERDICT = 38 class XDPAction: # from xdp_action uapi/linux/bpf.h XDP_ABORTED = 0 XDP_DROP = 1 XDP_PASS = 2 XDP_TX = 3 XDP_REDIRECT = 4 class XDPFlags: # from xdp_flags uapi/linux/if_link.h # unlike similar enum-type holder classes in this file, source for these # is #define XDP_FLAGS_UPDATE_IF_NOEXIST, #define XDP_FLAGS_SKB_MODE, ... UPDATE_IF_NOEXIST = (1 << 0) SKB_MODE = (1 << 1) DRV_MODE = (1 << 2) HW_MODE = (1 << 3) REPLACE = (1 << 4) class BPF(object): # Here for backwards compatibility only, add new enum members and types # the appropriate wrapper class elsewhere in this file to avoid namespace # collision issues SOCKET_FILTER = BPFProgType.SOCKET_FILTER KPROBE = BPFProgType.KPROBE SCHED_CLS = BPFProgType.SCHED_CLS SCHED_ACT = BPFProgType.SCHED_ACT TRACEPOINT = BPFProgType.TRACEPOINT XDP = BPFProgType.XDP PERF_EVENT = BPFProgType.PERF_EVENT CGROUP_SKB = BPFProgType.CGROUP_SKB CGROUP_SOCK = BPFProgType.CGROUP_SOCK LWT_IN = BPFProgType.LWT_IN LWT_OUT = BPFProgType.LWT_OUT LWT_XMIT = BPFProgType.LWT_XMIT SOCK_OPS = BPFProgType.SOCK_OPS SK_SKB = BPFProgType.SK_SKB CGROUP_DEVICE = BPFProgType.CGROUP_DEVICE SK_MSG = BPFProgType.SK_MSG RAW_TRACEPOINT = BPFProgType.RAW_TRACEPOINT CGROUP_SOCK_ADDR = BPFProgType.CGROUP_SOCK_ADDR TRACING = BPFProgType.TRACING LSM = BPFProgType.LSM XDP_ABORTED = XDPAction.XDP_ABORTED XDP_DROP = XDPAction.XDP_DROP XDP_PASS = XDPAction.XDP_PASS XDP_TX = XDPAction.XDP_TX XDP_REDIRECT = XDPAction.XDP_REDIRECT XDP_FLAGS_UPDATE_IF_NOEXIST = XDPFlags.UPDATE_IF_NOEXIST XDP_FLAGS_SKB_MODE = XDPFlags.SKB_MODE XDP_FLAGS_DRV_MODE = XDPFlags.DRV_MODE XDP_FLAGS_HW_MODE = XDPFlags.HW_MODE XDP_FLAGS_REPLACE = XDPFlags.REPLACE # END enum backwards compat _probe_repl = re.compile(b"[^a-zA-Z0-9_]") _sym_caches = {} _bsymcache = lib.bcc_buildsymcache_new() _auto_includes = { "linux/time.h": ["time"], "linux/fs.h": ["fs", "file"], "linux/blkdev.h": ["bio", "request"], "linux/slab.h": ["alloc"], "linux/netdevice.h": ["sk_buff", "net_device"] } _syscall_prefixes = [ b"sys_", b"__x64_sys_", b"__x32_compat_sys_", b"__ia32_compat_sys_", b"__arm64_sys_", b"__s390x_sys_", b"__s390_sys_", ] # BPF timestamps come from the monotonic clock. To be able to filter # and compare them from Python, we need to invoke clock_gettime. # Adapted from http://stackoverflow.com/a/1205762 CLOCK_MONOTONIC = 1 # see class timespec(ct.Structure): _fields_ = [('tv_sec', ct.c_long), ('tv_nsec', ct.c_long)] _librt = ct.CDLL('librt.so.1', use_errno=True) _clock_gettime = _librt.clock_gettime _clock_gettime.argtypes = [ct.c_int, ct.POINTER(timespec)] @classmethod def monotonic_time(cls): """monotonic_time() Returns the system monotonic time from clock_gettime, using the CLOCK_MONOTONIC constant. The time returned is in nanoseconds. """ t = cls.timespec() if cls._clock_gettime(cls.CLOCK_MONOTONIC, ct.byref(t)) != 0: errno = ct.get_errno() raise OSError(errno, os.strerror(errno)) return t.tv_sec * 1e9 + t.tv_nsec @classmethod def generate_auto_includes(cls, program_words): """ Generates #include statements automatically based on a set of recognized types such as sk_buff and bio. The input is all the words that appear in the BPF program, and the output is a (possibly empty) string of #include statements, such as "#include ". """ headers = "" for header, keywords in cls._auto_includes.items(): for keyword in keywords: for word in program_words: if keyword in word and header not in headers: headers += "#include <%s>\n" % header return headers # defined for compatibility reasons, to be removed Table = Table class Function(object): def __init__(self, bpf, name, fd): self.bpf = bpf self.name = name self.fd = fd @staticmethod def _find_file(filename): """ If filename is invalid, search in ./ of argv[0] """ if filename: if not os.path.isfile(filename): argv0 = ArgString(sys.argv[0]) t = b"/".join([os.path.abspath(os.path.dirname(argv0.__bytes__())), filename]) if os.path.isfile(t): filename = t else: raise Exception("Could not find file %s" % filename) return filename @staticmethod def find_exe(bin_path): """ find_exe(bin_path) Traverses the PATH environment variable, looking for the first directory that contains an executable file named bin_path, and returns the full path to that file, or None if no such file can be found. This is meant to replace invocations of the "which" shell utility, which doesn't have portable semantics for skipping aliases. """ # Source: http://stackoverflow.com/a/377028 def is_exe(fpath): return os.path.isfile(fpath) and \ os.access(fpath, os.X_OK) fpath, fname = os.path.split(bin_path) if fpath: if is_exe(bin_path): return bin_path else: for path in os.environ["PATH"].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path.encode(), bin_path) if is_exe(exe_file): return exe_file return None def __init__(self, src_file=b"", hdr_file=b"", text=None, debug=0, cflags=[], usdt_contexts=[], allow_rlimit=True, device=None, attach_usdt_ignore_pid=False): """Create a new BPF module with the given source code. Note: All fields are marked as optional, but either `src_file` or `text` must be supplied, and not both. Args: src_file (Optional[str]): Path to a source file for the module hdr_file (Optional[str]): Path to a helper header file for the `src_file` text (Optional[str]): Contents of a source file for the module debug (Optional[int]): Flags used for debug prints, can be |'d together See "Debug flags" for explanation """ src_file = _assert_is_bytes(src_file) hdr_file = _assert_is_bytes(hdr_file) text = _assert_is_bytes(text) assert not (text and src_file) self.kprobe_fds = {} self.uprobe_fds = {} self.tracepoint_fds = {} self.raw_tracepoint_fds = {} self.kfunc_entry_fds = {} self.kfunc_exit_fds = {} self.lsm_fds = {} self.perf_buffers = {} self.open_perf_events = {} self._ringbuf_manager = None self.tracefile = None atexit.register(self.cleanup) self.debug = debug self.funcs = {} self.tables = {} self.module = None cflags_array = (ct.c_char_p * len(cflags))() for i, s in enumerate(cflags): cflags_array[i] = bytes(ArgString(s)) if src_file: src_file = BPF._find_file(src_file) hdr_file = BPF._find_file(hdr_file) if src_file: # Read the BPF C source file into the text variable. This ensures, # that files and inline text are treated equally. with open(src_file, mode="rb") as file: text = file.read() ctx_array = (ct.c_void_p * len(usdt_contexts))() for i, usdt in enumerate(usdt_contexts): ctx_array[i] = ct.c_void_p(usdt.get_context()) usdt_text = lib.bcc_usdt_genargs(ctx_array, len(usdt_contexts)) if usdt_text is None: raise Exception("can't generate USDT probe arguments; " + "possible cause is missing pid when a " + "probe in a shared object has multiple " + "locations") text = usdt_text + text self.module = lib.bpf_module_create_c_from_string(text, self.debug, cflags_array, len(cflags_array), allow_rlimit, device) if not self.module: raise Exception("Failed to compile BPF module %s" % (src_file or "")) for usdt_context in usdt_contexts: usdt_context.attach_uprobes(self, attach_usdt_ignore_pid) # If any "kprobe__" or "tracepoint__" or "raw_tracepoint__" # prefixed functions were defined, # they will be loaded and attached here. self._trace_autoload() def load_funcs(self, prog_type=KPROBE): """load_funcs(prog_type=KPROBE) Load all functions in this BPF module with the given type. Returns a list of the function handles.""" fns = [] for i in range(0, lib.bpf_num_functions(self.module)): func_name = lib.bpf_function_name(self.module, i) fns.append(self.load_func(func_name, prog_type)) return fns def load_func(self, func_name, prog_type, device = None, attach_type = -1): func_name = _assert_is_bytes(func_name) if func_name in self.funcs: return self.funcs[func_name] if not lib.bpf_function_start(self.module, func_name): raise Exception("Unknown program %s" % func_name) log_level = 0 if (self.debug & DEBUG_BPF_REGISTER_STATE): log_level = 2 elif (self.debug & DEBUG_BPF): log_level = 1 fd = lib.bcc_func_load(self.module, prog_type, func_name, lib.bpf_function_start(self.module, func_name), lib.bpf_function_size(self.module, func_name), lib.bpf_module_license(self.module), lib.bpf_module_kern_version(self.module), log_level, None, 0, device, attach_type) if fd < 0: atexit.register(self.donothing) if ct.get_errno() == errno.EPERM: raise Exception("Need super-user privileges to run") errstr = os.strerror(ct.get_errno()) raise Exception("Failed to load BPF program %s: %s" % (func_name, errstr)) fn = BPF.Function(self, func_name, fd) self.funcs[func_name] = fn return fn def dump_func(self, func_name): """ Return the eBPF bytecodes for the specified function as a string """ func_name = _assert_is_bytes(func_name) if not lib.bpf_function_start(self.module, func_name): raise Exception("Unknown program %s" % func_name) start, = lib.bpf_function_start(self.module, func_name), size, = lib.bpf_function_size(self.module, func_name), return ct.string_at(start, size) def disassemble_func(self, func_name): bpfstr = self.dump_func(func_name) return disassemble_prog(func_name, bpfstr) def decode_table(self, table_name, sizeinfo=False): table_obj = self[table_name] table_type = lib.bpf_table_type_id(self.module, table_obj.map_id) return decode_map(table_name, table_obj, table_type, sizeinfo=sizeinfo) str2ctype = { u"_Bool": ct.c_bool, u"char": ct.c_char, u"wchar_t": ct.c_wchar, u"unsigned char": ct.c_ubyte, u"short": ct.c_short, u"unsigned short": ct.c_ushort, u"int": ct.c_int, u"unsigned int": ct.c_uint, u"long": ct.c_long, u"unsigned long": ct.c_ulong, u"long long": ct.c_longlong, u"unsigned long long": ct.c_ulonglong, u"float": ct.c_float, u"double": ct.c_double, u"long double": ct.c_longdouble, u"__int128": ct.c_int64 * 2, u"unsigned __int128": ct.c_uint64 * 2, } @staticmethod def _decode_table_type(desc): if isinstance(desc, basestring): return BPF.str2ctype[desc] anon = [] fields = [] for t in desc[1]: if len(t) == 2: fields.append((t[0], BPF._decode_table_type(t[1]))) elif len(t) == 3: if isinstance(t[2], list): fields.append((t[0], BPF._decode_table_type(t[1]) * t[2][0])) elif isinstance(t[2], int): fields.append((t[0], BPF._decode_table_type(t[1]), t[2])) elif isinstance(t[2], basestring) and ( t[2] == u"union" or t[2] == u"struct" or t[2] == u"struct_packed"): name = t[0] if name == "": name = "__anon%d" % len(anon) anon.append(name) fields.append((name, BPF._decode_table_type(t))) else: raise Exception("Failed to decode type %s" % str(t)) else: raise Exception("Failed to decode type %s" % str(t)) base = ct.Structure is_packed = False if len(desc) > 2: if desc[2] == u"union": base = ct.Union elif desc[2] == u"struct": base = ct.Structure elif desc[2] == u"struct_packed": base = ct.Structure is_packed = True if is_packed: cls = type(str(desc[0]), (base,), dict(_anonymous_=anon, _pack_=1, _fields_=fields)) else: cls = type(str(desc[0]), (base,), dict(_anonymous_=anon, _fields_=fields)) return cls def get_table(self, name, keytype=None, leaftype=None, reducer=None): name = _assert_is_bytes(name) map_id = lib.bpf_table_id(self.module, name) map_fd = lib.bpf_table_fd(self.module, name) is_queuestack = lib.bpf_table_type_id(self.module, map_id) in [BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK] if map_fd < 0: raise KeyError if not keytype and not is_queuestack: key_desc = lib.bpf_table_key_desc(self.module, name).decode("utf-8") if not key_desc: raise Exception("Failed to load BPF Table %s key desc" % name) keytype = BPF._decode_table_type(json.loads(key_desc)) if not leaftype: leaf_desc = lib.bpf_table_leaf_desc(self.module, name).decode("utf-8") if not leaf_desc: raise Exception("Failed to load BPF Table %s leaf desc" % name) leaftype = BPF._decode_table_type(json.loads(leaf_desc)) return Table(self, map_id, map_fd, keytype, leaftype, name, reducer=reducer) def __getitem__(self, key): if key not in self.tables: self.tables[key] = self.get_table(key) return self.tables[key] def __setitem__(self, key, leaf): self.tables[key] = leaf def __len__(self): return len(self.tables) def __delitem__(self, key): del self.tables[key] def __iter__(self): return self.tables.__iter__() @staticmethod def attach_func(fn, attachable_fd, attach_type, flags=0): if not isinstance(fn, BPF.Function): raise Exception("arg 1 must be of type BPF.Function") res = lib.bpf_prog_attach(fn.fd, attachable_fd, attach_type, flags) if res < 0: raise Exception("Failed to attach BPF function with attach_type "\ "{0}: {1}".format(attach_type, os.strerror(-res))) @staticmethod def detach_func(fn, attachable_fd, attach_type): if not isinstance(fn, BPF.Function): raise Exception("arg 1 must be of type BPF.Function") res = lib.bpf_prog_detach2(fn.fd, attachable_fd, attach_type) if res < 0: raise Exception("Failed to detach BPF function with attach_type "\ "{0}: {1}".format(attach_type, os.strerror(-res))) @staticmethod def attach_raw_socket(fn, dev): dev = _assert_is_bytes(dev) if not isinstance(fn, BPF.Function): raise Exception("arg 1 must be of type BPF.Function") sock = lib.bpf_open_raw_sock(dev) if sock < 0: errstr = os.strerror(ct.get_errno()) raise Exception("Failed to open raw device %s: %s" % (dev, errstr)) res = lib.bpf_attach_socket(sock, fn.fd) if res < 0: errstr = os.strerror(ct.get_errno()) raise Exception("Failed to attach BPF to device %s: %s" % (dev, errstr)) fn.sock = sock @staticmethod def get_kprobe_functions(event_re): blacklist_file = "%s/../kprobes/blacklist" % TRACEFS try: with open(blacklist_file, "rb") as blacklist_f: blacklist = set([line.rstrip().split()[1] for line in blacklist_f]) except IOError as e: if e.errno != errno.EPERM: raise e blacklist = set([]) fns = [] in_init_section = 0 in_irq_section = 0 with open("/proc/kallsyms", "rb") as avail_file: for line in avail_file: (t, fn) = line.rstrip().split()[1:3] # Skip all functions defined between __init_begin and # __init_end if in_init_section == 0: if fn == b'__init_begin': in_init_section = 1 continue elif in_init_section == 1: if fn == b'__init_end': in_init_section = 2 continue # Skip all functions defined between __irqentry_text_start and # __irqentry_text_end if in_irq_section == 0: if fn == b'__irqentry_text_start': in_irq_section = 1 continue # __irqentry_text_end is not always after # __irqentry_text_start. But only happens when # no functions between two irqentry_text elif fn == b'__irqentry_text_end': in_irq_section = 2 continue elif in_irq_section == 1: if fn == b'__irqentry_text_end': in_irq_section = 2 continue # All functions defined as NOKPROBE_SYMBOL() start with the # prefix _kbl_addr_*, blacklisting them by looking at the name # allows to catch also those symbols that are defined in kernel # modules. if fn.startswith(b'_kbl_addr_'): continue # Explicitly blacklist perf-related functions, they are all # non-attachable. elif fn.startswith(b'__perf') or fn.startswith(b'perf_'): continue # Exclude all static functions with prefix __SCT__, they are # all non-attachable elif fn.startswith(b'__SCT__'): continue # Exclude all gcc 8's extra .cold functions elif re.match(b'^.*\.cold(\.\d+)?$', fn): continue if (t.lower() in [b't', b'w']) and re.fullmatch(event_re, fn) \ and fn not in blacklist: fns.append(fn) return set(fns) # Some functions may appear more than once def _check_probe_quota(self, num_new_probes): global _num_open_probes if _num_open_probes + num_new_probes > BPF.get_probe_limit(): raise Exception("Number of open probes would exceed global quota") @staticmethod def get_probe_limit(): env_probe_limit = os.environ.get('BCC_PROBE_LIMIT') if env_probe_limit and env_probe_limit.isdigit(): return int(env_probe_limit) else: return _default_probe_limit def _add_kprobe_fd(self, ev_name, fn_name, fd): global _num_open_probes if ev_name not in self.kprobe_fds: self.kprobe_fds[ev_name] = {} self.kprobe_fds[ev_name][fn_name] = fd _num_open_probes += 1 def _del_kprobe_fd(self, ev_name, fn_name): global _num_open_probes del self.kprobe_fds[ev_name][fn_name] _num_open_probes -= 1 def _add_uprobe_fd(self, name, fd): global _num_open_probes self.uprobe_fds[name] = fd _num_open_probes += 1 def _del_uprobe_fd(self, name): global _num_open_probes del self.uprobe_fds[name] _num_open_probes -= 1 # Find current system's syscall prefix by testing on the BPF syscall. # If no valid value found, will return the first possible value which # would probably lead to error in later API calls. def get_syscall_prefix(self): for prefix in self._syscall_prefixes: if self.ksymname(b"%sbpf" % prefix) != -1: return prefix return self._syscall_prefixes[0] # Given a syscall's name, return the full Kernel function name with current # system's syscall prefix. For example, given "clone" the helper would # return "sys_clone" or "__x64_sys_clone". def get_syscall_fnname(self, name): name = _assert_is_bytes(name) return self.get_syscall_prefix() + name # Given a Kernel function name that represents a syscall but already has a # prefix included, transform it to current system's prefix. For example, # if "sys_clone" provided, the helper may translate it to "__x64_sys_clone". def fix_syscall_fnname(self, name): name = _assert_is_bytes(name) for prefix in self._syscall_prefixes: if name.startswith(prefix): return self.get_syscall_fnname(name[len(prefix):]) return name def attach_kprobe(self, event=b"", event_off=0, fn_name=b"", event_re=b""): event = _assert_is_bytes(event) fn_name = _assert_is_bytes(fn_name) event_re = _assert_is_bytes(event_re) # allow the caller to glob multiple functions together if event_re: matches = BPF.get_kprobe_functions(event_re) self._check_probe_quota(len(matches)) failed = 0 probes = [] for line in matches: try: self.attach_kprobe(event=line, fn_name=fn_name) except: failed += 1 probes.append(line) if failed == len(matches): raise Exception("Failed to attach BPF program %s to kprobe %s" ", it's not traceable (either non-existing, inlined, or marked as \"notrace\")" % (fn_name, '/'.join(probes))) return self._check_probe_quota(1) fn = self.load_func(fn_name, BPF.KPROBE) ev_name = b"p_" + event.replace(b"+", b"_").replace(b".", b"_") fd = lib.bpf_attach_kprobe(fn.fd, 0, ev_name, event, event_off, 0) if fd < 0: raise Exception("Failed to attach BPF program %s to kprobe %s" ", it's not traceable (either non-existing, inlined, or marked as \"notrace\")" % (fn_name, event)) self._add_kprobe_fd(ev_name, fn_name, fd) return self def attach_kretprobe(self, event=b"", fn_name=b"", event_re=b"", maxactive=0): event = _assert_is_bytes(event) fn_name = _assert_is_bytes(fn_name) event_re = _assert_is_bytes(event_re) # allow the caller to glob multiple functions together if event_re: matches = BPF.get_kprobe_functions(event_re) failed = 0 probes = [] for line in matches: try: self.attach_kretprobe(event=line, fn_name=fn_name, maxactive=maxactive) except: failed += 1 probes.append(line) if failed == len(matches): raise Exception("Failed to attach BPF program %s to kretprobe %s" ", it's not traceable (either non-existing, inlined, or marked as \"notrace\")" % (fn_name, '/'.join(probes))) return self._check_probe_quota(1) fn = self.load_func(fn_name, BPF.KPROBE) ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_") fd = lib.bpf_attach_kprobe(fn.fd, 1, ev_name, event, 0, maxactive) if fd < 0: raise Exception("Failed to attach BPF program %s to kretprobe %s" ", it's not traceable (either non-existing, inlined, or marked as \"notrace\")" % (fn_name, event)) self._add_kprobe_fd(ev_name, fn_name, fd) return self def detach_kprobe_event(self, ev_name): ev_name = _assert_is_bytes(ev_name) fn_names = list(self.kprobe_fds[ev_name].keys()) for fn_name in fn_names: self.detach_kprobe_event_by_fn(ev_name, fn_name) def detach_kprobe_event_by_fn(self, ev_name, fn_name): ev_name = _assert_is_bytes(ev_name) fn_name = _assert_is_bytes(fn_name) if ev_name not in self.kprobe_fds: raise Exception("Kprobe %s is not attached" % ev_name) res = lib.bpf_close_perf_event_fd(self.kprobe_fds[ev_name][fn_name]) if res < 0: raise Exception("Failed to close kprobe FD") self._del_kprobe_fd(ev_name, fn_name) if len(self.kprobe_fds[ev_name]) == 0: res = lib.bpf_detach_kprobe(ev_name) if res < 0: raise Exception("Failed to detach BPF from kprobe") def detach_kprobe(self, event, fn_name=None): event = _assert_is_bytes(event) ev_name = b"p_" + event.replace(b"+", b"_").replace(b".", b"_") if fn_name: fn_name = _assert_is_bytes(fn_name) self.detach_kprobe_event_by_fn(ev_name, fn_name) else: self.detach_kprobe_event(ev_name) def detach_kretprobe(self, event, fn_name=None): event = _assert_is_bytes(event) ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_") if fn_name: fn_name = _assert_is_bytes(fn_name) self.detach_kprobe_event_by_fn(ev_name, fn_name) else: self.detach_kprobe_event(ev_name) @staticmethod def attach_xdp(dev, fn, flags=0): ''' This function attaches a BPF function to a device on the device driver level (XDP) ''' dev = _assert_is_bytes(dev) if not isinstance(fn, BPF.Function): raise Exception("arg 1 must be of type BPF.Function") res = lib.bpf_attach_xdp(dev, fn.fd, flags) if res < 0: err_no = ct.get_errno() if err_no == errno.EBADMSG: raise Exception("Internal error while attaching BPF to device,"+ " try increasing the debug level!") else: errstr = os.strerror(err_no) raise Exception("Failed to attach BPF to device %s: %s" % (dev, errstr)) @staticmethod def remove_xdp(dev, flags=0): ''' This function removes any BPF function from a device on the device driver level (XDP) ''' dev = _assert_is_bytes(dev) res = lib.bpf_attach_xdp(dev, -1, flags) if res < 0: errstr = os.strerror(ct.get_errno()) raise Exception("Failed to detach BPF from device %s: %s" % (dev, errstr)) @classmethod def _check_path_symbol(cls, module, symname, addr, pid, sym_off=0): module = _assert_is_bytes(module) symname = _assert_is_bytes(symname) sym = bcc_symbol() c_pid = 0 if pid == -1 else pid if lib.bcc_resolve_symname( module, symname, addr or 0x0, c_pid, ct.cast(None, ct.POINTER(bcc_symbol_option)), ct.byref(sym), ) < 0: raise Exception("could not determine address of symbol %s in %s" % (symname.decode(), module.decode())) new_addr = sym.offset + sym_off module_path = ct.cast(sym.module, ct.c_char_p).value lib.bcc_procutils_free(sym.module) return module_path, new_addr @staticmethod def find_library(libname): libname = _assert_is_bytes(libname) res = lib.bcc_procutils_which_so(libname, 0) if not res: return None libpath = ct.cast(res, ct.c_char_p).value lib.bcc_procutils_free(res) return libpath @staticmethod def get_tracepoints(tp_re): results = [] events_dir = os.path.join(TRACEFS, "events") for category in os.listdir(events_dir): cat_dir = os.path.join(events_dir, category) if not os.path.isdir(cat_dir): continue for event in os.listdir(cat_dir): evt_dir = os.path.join(cat_dir, event) if os.path.isdir(evt_dir): tp = ("%s:%s" % (category, event)) if re.match(tp_re.decode(), tp): results.append(tp) return results @staticmethod def tracepoint_exists(category, event): evt_dir = os.path.join(TRACEFS, "events", category, event) return os.path.isdir(evt_dir) def attach_tracepoint(self, tp=b"", tp_re=b"", fn_name=b""): """attach_tracepoint(tp="", tp_re="", fn_name="") Run the bpf function denoted by fn_name every time the kernel tracepoint specified by 'tp' is hit. The optional parameters pid, cpu, and group_fd can be used to filter the probe. The tracepoint specification is simply the tracepoint category and the tracepoint name, separated by a colon. For example: sched:sched_switch, syscalls:sys_enter_bind, etc. Instead of a tracepoint name, a regular expression can be provided in tp_re. The program will then attach to tracepoints that match the provided regular expression. To obtain a list of kernel tracepoints, use the tplist tool or cat the file /sys/kernel/debug/tracing/available_events. Examples: BPF(text).attach_tracepoint(tp="sched:sched_switch", fn_name="on_switch") BPF(text).attach_tracepoint(tp_re="sched:.*", fn_name="on_switch") """ tp = _assert_is_bytes(tp) tp_re = _assert_is_bytes(tp_re) fn_name = _assert_is_bytes(fn_name) if tp_re: for tp in BPF.get_tracepoints(tp_re): self.attach_tracepoint(tp=tp, fn_name=fn_name) return fn = self.load_func(fn_name, BPF.TRACEPOINT) (tp_category, tp_name) = tp.split(b':') fd = lib.bpf_attach_tracepoint(fn.fd, tp_category, tp_name) if fd < 0: raise Exception("Failed to attach BPF program %s to tracepoint %s" % (fn_name, tp)) self.tracepoint_fds[tp] = fd return self def attach_raw_tracepoint(self, tp=b"", fn_name=b""): """attach_raw_tracepoint(self, tp=b"", fn_name=b"") Run the bpf function denoted by fn_name every time the kernel tracepoint specified by 'tp' is hit. The bpf function should be loaded as a RAW_TRACEPOINT type. The fn_name is the kernel tracepoint name, e.g., sched_switch, sys_enter_bind, etc. Examples: BPF(text).attach_raw_tracepoint(tp="sched_switch", fn_name="on_switch") """ tp = _assert_is_bytes(tp) if tp in self.raw_tracepoint_fds: raise Exception("Raw tracepoint %s has been attached" % tp) fn_name = _assert_is_bytes(fn_name) fn = self.load_func(fn_name, BPF.RAW_TRACEPOINT) fd = lib.bpf_attach_raw_tracepoint(fn.fd, tp) if fd < 0: raise Exception("Failed to attach BPF to raw tracepoint") self.raw_tracepoint_fds[tp] = fd return self def detach_raw_tracepoint(self, tp=b""): """detach_raw_tracepoint(tp="") Stop running the bpf function that is attached to the kernel tracepoint specified by 'tp'. Example: bpf.detach_raw_tracepoint("sched_switch") """ tp = _assert_is_bytes(tp) if tp not in self.raw_tracepoint_fds: raise Exception("Raw tracepoint %s is not attached" % tp) os.close(self.raw_tracepoint_fds[tp]) del self.raw_tracepoint_fds[tp] @staticmethod def add_prefix(prefix, name): if not name.startswith(prefix): name = prefix + name return name @staticmethod def support_kfunc(): # there's no trampoline support for other than x86_64 arch if platform.machine() != 'x86_64': return False if not lib.bpf_has_kernel_btf(): return False # kernel symbol "bpf_trampoline_link_prog" indicates kfunc support if BPF.ksymname("bpf_trampoline_link_prog") != -1: return True return False @staticmethod def support_lsm(): if not lib.bpf_has_kernel_btf(): return False # kernel symbol "bpf_lsm_bpf" indicates BPF LSM support if BPF.ksymname(b"bpf_lsm_bpf") != -1: return True return False def detach_kfunc(self, fn_name=b""): fn_name = _assert_is_bytes(fn_name) fn_name = BPF.add_prefix(b"kfunc__", fn_name) if fn_name not in self.kfunc_entry_fds: raise Exception("Kernel entry func %s is not attached" % fn_name) os.close(self.kfunc_entry_fds[fn_name]) del self.kfunc_entry_fds[fn_name] def detach_kretfunc(self, fn_name=b""): fn_name = _assert_is_bytes(fn_name) fn_name = BPF.add_prefix(b"kretfunc__", fn_name) if fn_name not in self.kfunc_exit_fds: raise Exception("Kernel exit func %s is not attached" % fn_name) os.close(self.kfunc_exit_fds[fn_name]) del self.kfunc_exit_fds[fn_name] def attach_kfunc(self, fn_name=b""): fn_name = _assert_is_bytes(fn_name) fn_name = BPF.add_prefix(b"kfunc__", fn_name) if fn_name in self.kfunc_entry_fds: raise Exception("Kernel entry func %s has been attached" % fn_name) fn = self.load_func(fn_name, BPF.TRACING) fd = lib.bpf_attach_kfunc(fn.fd) if fd < 0: raise Exception("Failed to attach BPF to entry kernel func") self.kfunc_entry_fds[fn_name] = fd return self def attach_kretfunc(self, fn_name=b""): fn_name = _assert_is_bytes(fn_name) fn_name = BPF.add_prefix(b"kretfunc__", fn_name) if fn_name in self.kfunc_exit_fds: raise Exception("Kernel exit func %s has been attached" % fn_name) fn = self.load_func(fn_name, BPF.TRACING) fd = lib.bpf_attach_kfunc(fn.fd) if fd < 0: raise Exception("Failed to attach BPF to exit kernel func") self.kfunc_exit_fds[fn_name] = fd return self def detach_lsm(self, fn_name=b""): fn_name = _assert_is_bytes(fn_name) fn_name = BPF.add_prefix(b"lsm__", fn_name) if fn_name not in self.lsm_fds: raise Exception("LSM %s is not attached" % fn_name) os.close(self.lsm_fds[fn_name]) del self.lsm_fds[fn_name] def attach_lsm(self, fn_name=b""): fn_name = _assert_is_bytes(fn_name) fn_name = BPF.add_prefix(b"lsm__", fn_name) if fn_name in self.lsm_fds: raise Exception("LSM %s has been attached" % fn_name) fn = self.load_func(fn_name, BPF.LSM) fd = lib.bpf_attach_lsm(fn.fd) if fd < 0: raise Exception("Failed to attach LSM") self.lsm_fds[fn_name] = fd return self @staticmethod def support_raw_tracepoint(): # kernel symbol "bpf_find_raw_tracepoint" indicates raw_tracepoint support if BPF.ksymname("bpf_find_raw_tracepoint") != -1 or \ BPF.ksymname("bpf_get_raw_tracepoint") != -1: return True return False @staticmethod def support_raw_tracepoint_in_module(): # kernel symbol "bpf_trace_modules" indicates raw tp support in modules, ref: kernel commit a38d1107 kallsyms = "/proc/kallsyms" with open(kallsyms) as syms: for line in syms: (_, _, name) = line.rstrip().split(" ", 2) name = name.split("\t")[0] if name == "bpf_trace_modules": return True return False @staticmethod def kernel_struct_has_field(struct_name, field_name): struct_name = _assert_is_bytes(struct_name) field_name = _assert_is_bytes(field_name) return lib.kernel_struct_has_field(struct_name, field_name) def detach_tracepoint(self, tp=b""): """detach_tracepoint(tp="") Stop running a bpf function that is attached to the kernel tracepoint specified by 'tp'. Example: bpf.detach_tracepoint("sched:sched_switch") """ tp = _assert_is_bytes(tp) if tp not in self.tracepoint_fds: raise Exception("Tracepoint %s is not attached" % tp) res = lib.bpf_close_perf_event_fd(self.tracepoint_fds[tp]) if res < 0: raise Exception("Failed to detach BPF from tracepoint") (tp_category, tp_name) = tp.split(b':') res = lib.bpf_detach_tracepoint(tp_category, tp_name) if res < 0: raise Exception("Failed to detach BPF from tracepoint") del self.tracepoint_fds[tp] def _attach_perf_event(self, progfd, ev_type, ev_config, sample_period, sample_freq, pid, cpu, group_fd): res = lib.bpf_attach_perf_event(progfd, ev_type, ev_config, sample_period, sample_freq, pid, cpu, group_fd) if res < 0: raise Exception("Failed to attach BPF to perf event") return res def attach_perf_event(self, ev_type=-1, ev_config=-1, fn_name=b"", sample_period=0, sample_freq=0, pid=-1, cpu=-1, group_fd=-1): fn_name = _assert_is_bytes(fn_name) fn = self.load_func(fn_name, BPF.PERF_EVENT) res = {} if cpu >= 0: res[cpu] = self._attach_perf_event(fn.fd, ev_type, ev_config, sample_period, sample_freq, pid, cpu, group_fd) else: for i in get_online_cpus(): res[i] = self._attach_perf_event(fn.fd, ev_type, ev_config, sample_period, sample_freq, pid, i, group_fd) self.open_perf_events[(ev_type, ev_config)] = res def _attach_perf_event_raw(self, progfd, attr, pid, cpu, group_fd): res = lib.bpf_attach_perf_event_raw(progfd, ct.byref(attr), pid, cpu, group_fd, 0) if res < 0: raise Exception("Failed to attach BPF to perf raw event") return res def attach_perf_event_raw(self, attr=-1, fn_name=b"", pid=-1, cpu=-1, group_fd=-1): fn_name = _assert_is_bytes(fn_name) fn = self.load_func(fn_name, BPF.PERF_EVENT) res = {} if cpu >= 0: res[cpu] = self._attach_perf_event_raw(fn.fd, attr, pid, cpu, group_fd) else: for i in get_online_cpus(): res[i] = self._attach_perf_event_raw(fn.fd, attr, pid, i, group_fd) self.open_perf_events[(attr.type, attr.config)] = res def detach_perf_event(self, ev_type=-1, ev_config=-1): try: fds = self.open_perf_events[(ev_type, ev_config)] except KeyError: raise Exception("Perf event type {} config {} not attached".format( ev_type, ev_config)) res = 0 for fd in fds.values(): res = lib.bpf_close_perf_event_fd(fd) or res if res != 0: raise Exception("Failed to detach BPF from perf event") del self.open_perf_events[(ev_type, ev_config)] @staticmethod def get_user_functions(name, sym_re): return set([name for (name, _) in BPF.get_user_functions_and_addresses(name, sym_re)]) @staticmethod def get_user_addresses(name, sym_re): """ We are returning addresses here instead of symbol names because it turns out that the same name may appear multiple times with different addresses, and the same address may appear multiple times with the same name. We can't attach a uprobe to the same address more than once, so it makes sense to return the unique set of addresses that are mapped to a symbol that matches the provided regular expression. """ return set([address for (_, address) in BPF.get_user_functions_and_addresses(name, sym_re)]) @staticmethod def get_user_functions_and_addresses(name, sym_re): name = _assert_is_bytes(name) sym_re = _assert_is_bytes(sym_re) addresses = [] def sym_cb(sym_name, addr): dname = sym_name if re.match(sym_re, dname): addresses.append((dname, addr)) return 0 res = lib.bcc_foreach_function_symbol(name, _SYM_CB_TYPE(sym_cb)) if res < 0: raise Exception("Error %d enumerating symbols in %s" % (res, name)) return addresses def _get_uprobe_evname(self, prefix, path, addr, pid): if pid == -1: return b"%s_%s_0x%x" % (prefix, self._probe_repl.sub(b"_", path), addr) else: # if pid is valid, put pid in the name, so different pid # can have different event names return b"%s_%s_0x%x_%d" % (prefix, self._probe_repl.sub(b"_", path), addr, pid) def attach_uprobe(self, name=b"", sym=b"", sym_re=b"", addr=None, fn_name=b"", pid=-1, sym_off=0): """attach_uprobe(name="", sym="", sym_re="", addr=None, fn_name="" pid=-1, sym_off=0) Run the bpf function denoted by fn_name every time the symbol sym in the library or binary 'name' is encountered. Optional parameters pid, cpu, and group_fd can be used to filter the probe. If sym_off is given, attach uprobe to offset within the symbol. The real address addr may be supplied in place of sym, in which case sym must be set to its default value. If the file is a non-PIE executable, addr must be a virtual address, otherwise it must be an offset relative to the file load address. Instead of a symbol name, a regular expression can be provided in sym_re. The uprobe will then attach to symbols that match the provided regular expression. Libraries can be given in the name argument without the lib prefix, or with the full path (/usr/lib/...). Binaries can be given only with the full path (/bin/sh). If a PID is given, the uprobe will attach to the version of the library used by the process. Example: BPF(text).attach_uprobe("c", "malloc") BPF(text).attach_uprobe("/usr/bin/python", "main") """ assert sym_off >= 0 if addr is not None: assert sym_off == 0, "offset with addr is not supported" name = _assert_is_bytes(name) sym = _assert_is_bytes(sym) sym_re = _assert_is_bytes(sym_re) fn_name = _assert_is_bytes(fn_name) if sym_re: addresses = BPF.get_user_addresses(name, sym_re) self._check_probe_quota(len(addresses)) for sym_addr in addresses: self.attach_uprobe(name=name, addr=sym_addr, fn_name=fn_name, pid=pid) return (path, addr) = BPF._check_path_symbol(name, sym, addr, pid, sym_off) self._check_probe_quota(1) fn = self.load_func(fn_name, BPF.KPROBE) ev_name = self._get_uprobe_evname(b"p", path, addr, pid) fd = lib.bpf_attach_uprobe(fn.fd, 0, ev_name, path, addr, pid) if fd < 0: raise Exception("Failed to attach BPF to uprobe") self._add_uprobe_fd(ev_name, fd) return self def attach_uretprobe(self, name=b"", sym=b"", sym_re=b"", addr=None, fn_name=b"", pid=-1): """attach_uretprobe(name="", sym="", sym_re="", addr=None, fn_name="" pid=-1) Run the bpf function denoted by fn_name every time the symbol sym in the library or binary 'name' finishes execution. See attach_uprobe for meaning of additional parameters. """ name = _assert_is_bytes(name) sym = _assert_is_bytes(sym) sym_re = _assert_is_bytes(sym_re) fn_name = _assert_is_bytes(fn_name) if sym_re: for sym_addr in BPF.get_user_addresses(name, sym_re): self.attach_uretprobe(name=name, addr=sym_addr, fn_name=fn_name, pid=pid) return (path, addr) = BPF._check_path_symbol(name, sym, addr, pid) self._check_probe_quota(1) fn = self.load_func(fn_name, BPF.KPROBE) ev_name = self._get_uprobe_evname(b"r", path, addr, pid) fd = lib.bpf_attach_uprobe(fn.fd, 1, ev_name, path, addr, pid) if fd < 0: raise Exception("Failed to attach BPF to uretprobe") self._add_uprobe_fd(ev_name, fd) return self def detach_uprobe_event(self, ev_name): if ev_name not in self.uprobe_fds: raise Exception("Uprobe %s is not attached" % ev_name) res = lib.bpf_close_perf_event_fd(self.uprobe_fds[ev_name]) if res < 0: raise Exception("Failed to detach BPF from uprobe") res = lib.bpf_detach_uprobe(ev_name) if res < 0: raise Exception("Failed to detach BPF from uprobe") self._del_uprobe_fd(ev_name) def detach_uprobe(self, name=b"", sym=b"", addr=None, pid=-1, sym_off=0): """detach_uprobe(name="", sym="", addr=None, pid=-1) Stop running a bpf function that is attached to symbol 'sym' in library or binary 'name'. """ name = _assert_is_bytes(name) sym = _assert_is_bytes(sym) (path, addr) = BPF._check_path_symbol(name, sym, addr, pid, sym_off) ev_name = self._get_uprobe_evname(b"p", path, addr, pid) self.detach_uprobe_event(ev_name) def detach_uretprobe(self, name=b"", sym=b"", addr=None, pid=-1): """detach_uretprobe(name="", sym="", addr=None, pid=-1) Stop running a bpf function that is attached to symbol 'sym' in library or binary 'name'. """ name = _assert_is_bytes(name) sym = _assert_is_bytes(sym) (path, addr) = BPF._check_path_symbol(name, sym, addr, pid) ev_name = self._get_uprobe_evname(b"r", path, addr, pid) self.detach_uprobe_event(ev_name) def _trace_autoload(self): for i in range(0, lib.bpf_num_functions(self.module)): func_name = lib.bpf_function_name(self.module, i) if func_name.startswith(b"kprobe__"): fn = self.load_func(func_name, BPF.KPROBE) self.attach_kprobe( event=self.fix_syscall_fnname(func_name[8:]), fn_name=fn.name) elif func_name.startswith(b"kretprobe__"): fn = self.load_func(func_name, BPF.KPROBE) self.attach_kretprobe( event=self.fix_syscall_fnname(func_name[11:]), fn_name=fn.name) elif func_name.startswith(b"tracepoint__"): fn = self.load_func(func_name, BPF.TRACEPOINT) tp = fn.name[len(b"tracepoint__"):].replace(b"__", b":") self.attach_tracepoint(tp=tp, fn_name=fn.name) elif func_name.startswith(b"raw_tracepoint__"): fn = self.load_func(func_name, BPF.RAW_TRACEPOINT) tp = fn.name[len(b"raw_tracepoint__"):] self.attach_raw_tracepoint(tp=tp, fn_name=fn.name) elif func_name.startswith(b"kfunc__"): self.attach_kfunc(fn_name=func_name) elif func_name.startswith(b"kretfunc__"): self.attach_kretfunc(fn_name=func_name) elif func_name.startswith(b"lsm__"): self.attach_lsm(fn_name=func_name) def trace_open(self, nonblocking=False): """trace_open(nonblocking=False) Open the trace_pipe if not already open """ if not self.tracefile: self.tracefile = open("%s/trace_pipe" % TRACEFS, "rb") if nonblocking: fd = self.tracefile.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) return self.tracefile def trace_fields(self, nonblocking=False): """trace_fields(nonblocking=False) Read from the kernel debug trace pipe and return a tuple of the fields (task, pid, cpu, flags, timestamp, msg) or None if no line was read (nonblocking=True) """ while True: line = self.trace_readline(nonblocking) if not line and nonblocking: return (None,) * 6 # don't print messages related to lost events if line.startswith(b"CPU:"): continue task = line[:16].lstrip() line = line[17:] ts_end = line.find(b":") try: pid, cpu, flags, ts = line[:ts_end].split() except Exception as e: continue cpu = cpu[1:-1] # line[ts_end:] will have ": [sym_or_addr]: msgs" # For trace_pipe debug output, the addr typically # is invalid (e.g., 0x1). For kernel 4.12 or earlier, # if address is not able to match a kernel symbol, # nothing will be printed out. For kernel 4.13 and later, # however, the illegal address will be printed out. # Hence, both cases are handled here. line = line[ts_end + 1:] sym_end = line.find(b":") msg = line[sym_end + 2:] try: return (task, int(pid), int(cpu), flags, float(ts), msg) except Exception as e: return ("Unknown", 0, 0, "Unknown", 0.0, "Unknown") def trace_readline(self, nonblocking=False): """trace_readline(nonblocking=False) Read from the kernel debug trace pipe and return one line If nonblocking is False, this will block until ctrl-C is pressed. """ trace = self.trace_open(nonblocking) line = None try: line = trace.readline(1024).rstrip() except IOError: pass return line def trace_print(self, fmt=None): """trace_print(self, fmt=None) Read from the kernel debug trace pipe and print on stdout. If fmt is specified, apply as a format string to the output. See trace_fields for the members of the tuple example: trace_print(fmt="pid {1}, msg = {5}") """ while True: if fmt: fields = self.trace_fields(nonblocking=False) if not fields: continue line = fmt.format(*fields) else: line = self.trace_readline(nonblocking=False) print(line) sys.stdout.flush() @staticmethod def _sym_cache(pid): """_sym_cache(pid) Returns a symbol cache for the specified PID. The kernel symbol cache is accessed by providing any PID less than zero. """ if pid < 0 and pid != -1: pid = -1 if not pid in BPF._sym_caches: BPF._sym_caches[pid] = SymbolCache(pid) return BPF._sym_caches[pid] @staticmethod def sym(addr, pid, show_module=False, show_offset=False, demangle=True): """sym(addr, pid, show_module=False, show_offset=False) Translate a memory address into a function name for a pid, which is returned. When show_module is True, the module name is also included. When show_offset is True, the instruction offset as a hexadecimal number is also included in the string. A pid of less than zero will access the kernel symbol cache. Example output when both show_module and show_offset are True: "start_thread+0x202 [libpthread-2.24.so]" Example output when both show_module and show_offset are False: "start_thread" """ #addr is of type stacktrace_build_id #so invoke the bsym address resolver typeofaddr = str(type(addr)) if typeofaddr.find('bpf_stack_build_id') != -1: sym = bcc_symbol() b = bcc_stacktrace_build_id() b.status = addr.status b.build_id = addr.build_id b.u.offset = addr.offset res = lib.bcc_buildsymcache_resolve(BPF._bsymcache, ct.byref(b), ct.byref(sym)) if res < 0: if sym.module and sym.offset: name,offset,module = (None, sym.offset, ct.cast(sym.module, ct.c_char_p).value) else: name, offset, module = (None, addr, None) else: name, offset, module = (sym.name, sym.offset, ct.cast(sym.module, ct.c_char_p).value) else: name, offset, module = BPF._sym_cache(pid).resolve(addr, demangle) offset = b"+0x%x" % offset if show_offset and name is not None else b"" name = name or b"[unknown]" name = name + offset module = b" [%s]" % os.path.basename(module) \ if show_module and module is not None else b"" return name + module @staticmethod def ksym(addr, show_module=False, show_offset=False): """ksym(addr) Translate a kernel memory address into a kernel function name, which is returned. When show_module is True, the module name ("kernel") is also included. When show_offset is true, the instruction offset as a hexadecimal number is also included in the string. Example output when both show_module and show_offset are True: "default_idle+0x0 [kernel]" """ return BPF.sym(addr, -1, show_module, show_offset, False) @staticmethod def ksymname(name): """ksymname(name) Translate a kernel name into an address. This is the reverse of ksym. Returns -1 when the function name is unknown.""" return BPF._sym_cache(-1).resolve_name(None, name) def num_open_kprobes(self): """num_open_kprobes() Get the number of open K[ret]probes. Can be useful for scenarios where event_re is used while attaching and detaching probes. """ return len(self.kprobe_fds) def num_open_uprobes(self): """num_open_uprobes() Get the number of open U[ret]probes. """ return len(self.uprobe_fds) def num_open_tracepoints(self): """num_open_tracepoints() Get the number of open tracepoints. """ return len(self.tracepoint_fds) def perf_buffer_poll(self, timeout = -1): """perf_buffer_poll(self) Poll from all open perf ring buffers, calling the callback that was provided when calling open_perf_buffer for each entry. """ readers = (ct.c_void_p * len(self.perf_buffers))() for i, v in enumerate(self.perf_buffers.values()): readers[i] = v lib.perf_reader_poll(len(readers), readers, timeout) def perf_buffer_consume(self): """perf_buffer_consume(self) Consume all open perf buffers, regardless of whether or not they currently contain events data. Necessary to catch 'remainder' events when wakeup_events > 1 is set in open_perf_buffer """ readers = (ct.c_void_p * len(self.perf_buffers))() for i, v in enumerate(self.perf_buffers.values()): readers[i] = v lib.perf_reader_consume(len(readers), readers) def kprobe_poll(self, timeout = -1): """kprobe_poll(self) Deprecated. Use perf_buffer_poll instead. """ self.perf_buffer_poll(timeout) def _open_ring_buffer(self, map_fd, fn, ctx=None): if not self._ringbuf_manager: self._ringbuf_manager = lib.bpf_new_ringbuf(map_fd, fn, ctx) if not self._ringbuf_manager: raise Exception("Could not open ring buffer") else: ret = lib.bpf_add_ringbuf(self._ringbuf_manager, map_fd, fn, ctx) if ret < 0: raise Exception("Could not open ring buffer") def ring_buffer_poll(self, timeout = -1): """ring_buffer_poll(self) Poll from all open ringbuf buffers, calling the callback that was provided when calling open_ring_buffer for each entry. """ if not self._ringbuf_manager: raise Exception("No ring buffers to poll") lib.bpf_poll_ringbuf(self._ringbuf_manager, timeout) def ring_buffer_consume(self): """ring_buffer_consume(self) Consume all open ringbuf buffers, regardless of whether or not they currently contain events data. This is best for use cases where low latency is desired, but it can impact performance. If you are unsure, use ring_buffer_poll instead. """ if not self._ringbuf_manager: raise Exception("No ring buffers to poll") lib.bpf_consume_ringbuf(self._ringbuf_manager) def free_bcc_memory(self): return lib.bcc_free_memory() @staticmethod def add_module(modname): """add_module(modname) Add a library or exe to buildsym cache """ try: lib.bcc_buildsymcache_add_module(BPF._bsymcache, modname.encode()) except Exception as e: print("Error adding module to build sym cache"+str(e)) def donothing(self): """the do nothing exit handler""" def close(self): """close(self) Closes all associated files descriptors. Attached BPF programs are not detached. """ for name, fn in list(self.funcs.items()): os.close(fn.fd) del self.funcs[name] if self.module: lib.bpf_module_destroy(self.module) self.module = None def cleanup(self): # Clean up opened probes for k, v in list(self.kprobe_fds.items()): self.detach_kprobe_event(k) for k, v in list(self.uprobe_fds.items()): self.detach_uprobe_event(k) for k, v in list(self.tracepoint_fds.items()): self.detach_tracepoint(k) for k, v in list(self.raw_tracepoint_fds.items()): self.detach_raw_tracepoint(k) for k, v in list(self.kfunc_entry_fds.items()): self.detach_kfunc(k) for k, v in list(self.kfunc_exit_fds.items()): self.detach_kretfunc(k) for k, v in list(self.lsm_fds.items()): self.detach_lsm(k) # Clean up opened perf ring buffer and perf events table_keys = list(self.tables.keys()) for key in table_keys: if isinstance(self.tables[key], PerfEventArray): del self.tables[key] for (ev_type, ev_config) in list(self.open_perf_events.keys()): self.detach_perf_event(ev_type, ev_config) if self.tracefile: self.tracefile.close() self.tracefile = None self.close() # Clean up ringbuf if self._ringbuf_manager: lib.bpf_free_ringbuf(self._ringbuf_manager) self._ringbuf_manager = None def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.cleanup() syscall.py000064400000022670152344707330006607 0ustar00# Copyright 2017 Sasha Goldshtein # Copyright 2018 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """syscall.py contains functions useful for mapping between syscall names and numbers""" import subprocess import platform # # Syscall table for Linux x86_64, not very recent. # Automatically generated from strace/linux/x86_64/syscallent.h using the # following command: # # cat syscallent.h | awk -F, '{ gsub(/[ \t"}]/, "", $4); # gsub(/[\[\] \t{]/, "", $1); split($1, a, "="); # print " "a[1]": b\""$4"\","; } # BEGIN { print "syscalls = {" } # END { print "}" '} syscalls = { 0: b"read", 1: b"write", 2: b"open", 3: b"close", 4: b"stat", 5: b"fstat", 6: b"lstat", 7: b"poll", 8: b"lseek", 9: b"mmap", 10: b"mprotect", 11: b"munmap", 12: b"brk", 13: b"rt_sigaction", 14: b"rt_sigprocmask", 15: b"rt_sigreturn", 16: b"ioctl", 17: b"pread64", 18: b"pwrite64", 19: b"readv", 20: b"writev", 21: b"access", 22: b"pipe", 23: b"select", 24: b"sched_yield", 25: b"mremap", 26: b"msync", 27: b"mincore", 28: b"madvise", 29: b"shmget", 30: b"shmat", 31: b"shmctl", 32: b"dup", 33: b"dup2", 34: b"pause", 35: b"nanosleep", 36: b"getitimer", 37: b"alarm", 38: b"setitimer", 39: b"getpid", 40: b"sendfile", 41: b"socket", 42: b"connect", 43: b"accept", 44: b"sendto", 45: b"recvfrom", 46: b"sendmsg", 47: b"recvmsg", 48: b"shutdown", 49: b"bind", 50: b"listen", 51: b"getsockname", 52: b"getpeername", 53: b"socketpair", 54: b"setsockopt", 55: b"getsockopt", 56: b"clone", 57: b"fork", 58: b"vfork", 59: b"execve", 60: b"exit", 61: b"wait4", 62: b"kill", 63: b"uname", 64: b"semget", 65: b"semop", 66: b"semctl", 67: b"shmdt", 68: b"msgget", 69: b"msgsnd", 70: b"msgrcv", 71: b"msgctl", 72: b"fcntl", 73: b"flock", 74: b"fsync", 75: b"fdatasync", 76: b"truncate", 77: b"ftruncate", 78: b"getdents", 79: b"getcwd", 80: b"chdir", 81: b"fchdir", 82: b"rename", 83: b"mkdir", 84: b"rmdir", 85: b"creat", 86: b"link", 87: b"unlink", 88: b"symlink", 89: b"readlink", 90: b"chmod", 91: b"fchmod", 92: b"chown", 93: b"fchown", 94: b"lchown", 95: b"umask", 96: b"gettimeofday", 97: b"getrlimit", 98: b"getrusage", 99: b"sysinfo", 100: b"times", 101: b"ptrace", 102: b"getuid", 103: b"syslog", 104: b"getgid", 105: b"setuid", 106: b"setgid", 107: b"geteuid", 108: b"getegid", 109: b"setpgid", 110: b"getppid", 111: b"getpgrp", 112: b"setsid", 113: b"setreuid", 114: b"setregid", 115: b"getgroups", 116: b"setgroups", 117: b"setresuid", 118: b"getresuid", 119: b"setresgid", 120: b"getresgid", 121: b"getpgid", 122: b"setfsuid", 123: b"setfsgid", 124: b"getsid", 125: b"capget", 126: b"capset", 127: b"rt_sigpending", 128: b"rt_sigtimedwait", 129: b"rt_sigqueueinfo", 130: b"rt_sigsuspend", 131: b"sigaltstack", 132: b"utime", 133: b"mknod", 134: b"uselib", 135: b"personality", 136: b"ustat", 137: b"statfs", 138: b"fstatfs", 139: b"sysfs", 140: b"getpriority", 141: b"setpriority", 142: b"sched_setparam", 143: b"sched_getparam", 144: b"sched_setscheduler", 145: b"sched_getscheduler", 146: b"sched_get_priority_max", 147: b"sched_get_priority_min", 148: b"sched_rr_get_interval", 149: b"mlock", 150: b"munlock", 151: b"mlockall", 152: b"munlockall", 153: b"vhangup", 154: b"modify_ldt", 155: b"pivot_root", 156: b"_sysctl", 157: b"prctl", 158: b"arch_prctl", 159: b"adjtimex", 160: b"setrlimit", 161: b"chroot", 162: b"sync", 163: b"acct", 164: b"settimeofday", 165: b"mount", 166: b"umount2", 167: b"swapon", 168: b"swapoff", 169: b"reboot", 170: b"sethostname", 171: b"setdomainname", 172: b"iopl", 173: b"ioperm", 174: b"create_module", 175: b"init_module", 176: b"delete_module", 177: b"get_kernel_syms", 178: b"query_module", 179: b"quotactl", 180: b"nfsservctl", 181: b"getpmsg", 182: b"putpmsg", 183: b"afs_syscall", 184: b"tuxcall", 185: b"security", 186: b"gettid", 187: b"readahead", 188: b"setxattr", 189: b"lsetxattr", 190: b"fsetxattr", 191: b"getxattr", 192: b"lgetxattr", 193: b"fgetxattr", 194: b"listxattr", 195: b"llistxattr", 196: b"flistxattr", 197: b"removexattr", 198: b"lremovexattr", 199: b"fremovexattr", 200: b"tkill", 201: b"time", 202: b"futex", 203: b"sched_setaffinity", 204: b"sched_getaffinity", 205: b"set_thread_area", 206: b"io_setup", 207: b"io_destroy", 208: b"io_getevents", 209: b"io_submit", 210: b"io_cancel", 211: b"get_thread_area", 212: b"lookup_dcookie", 213: b"epoll_create", 214: b"epoll_ctl_old", 215: b"epoll_wait_old", 216: b"remap_file_pages", 217: b"getdents64", 218: b"set_tid_address", 219: b"restart_syscall", 220: b"semtimedop", 221: b"fadvise64", 222: b"timer_create", 223: b"timer_settime", 224: b"timer_gettime", 225: b"timer_getoverrun", 226: b"timer_delete", 227: b"clock_settime", 228: b"clock_gettime", 229: b"clock_getres", 230: b"clock_nanosleep", 231: b"exit_group", 232: b"epoll_wait", 233: b"epoll_ctl", 234: b"tgkill", 235: b"utimes", 236: b"vserver", 237: b"mbind", 238: b"set_mempolicy", 239: b"get_mempolicy", 240: b"mq_open", 241: b"mq_unlink", 242: b"mq_timedsend", 243: b"mq_timedreceive", 244: b"mq_notify", 245: b"mq_getsetattr", 246: b"kexec_load", 247: b"waitid", 248: b"add_key", 249: b"request_key", 250: b"keyctl", 251: b"ioprio_set", 252: b"ioprio_get", 253: b"inotify_init", 254: b"inotify_add_watch", 255: b"inotify_rm_watch", 256: b"migrate_pages", 257: b"openat", 258: b"mkdirat", 259: b"mknodat", 260: b"fchownat", 261: b"futimesat", 262: b"newfstatat", 263: b"unlinkat", 264: b"renameat", 265: b"linkat", 266: b"symlinkat", 267: b"readlinkat", 268: b"fchmodat", 269: b"faccessat", 270: b"pselect6", 271: b"ppoll", 272: b"unshare", 273: b"set_robust_list", 274: b"get_robust_list", 275: b"splice", 276: b"tee", 277: b"sync_file_range", 278: b"vmsplice", 279: b"move_pages", 280: b"utimensat", 281: b"epoll_pwait", 282: b"signalfd", 283: b"timerfd_create", 284: b"eventfd", 285: b"fallocate", 286: b"timerfd_settime", 287: b"timerfd_gettime", 288: b"accept4", 289: b"signalfd4", 290: b"eventfd2", 291: b"epoll_create1", 292: b"dup3", 293: b"pipe2", 294: b"inotify_init1", 295: b"preadv", 296: b"pwritev", 297: b"rt_tgsigqueueinfo", 298: b"perf_event_open", 299: b"recvmmsg", 300: b"fanotify_init", 301: b"fanotify_mark", 302: b"prlimit64", 303: b"name_to_handle_at", 304: b"open_by_handle_at", 305: b"clock_adjtime", 306: b"syncfs", 307: b"sendmmsg", 308: b"setns", 309: b"getcpu", 310: b"process_vm_readv", 311: b"process_vm_writev", 312: b"kcmp", 313: b"finit_module", 314: b"sched_setattr", 315: b"sched_getattr", 316: b"renameat2", 317: b"seccomp", 318: b"getrandom", 319: b"memfd_create", 320: b"kexec_file_load", 321: b"bpf", 322: b"execveat", 323: b"userfaultfd", 324: b"membarrier", 325: b"mlock2", 326: b"copy_file_range", 327: b"preadv2", 328: b"pwritev2", 329: b"pkey_mprotect", 330: b"pkey_alloc", 331: b"pkey_free", 332: b"statx", 333: b"io_pgetevents", 334: b"rseq", } # Try to use ausyscall if it is available, because it can give us an up-to-date # list of syscalls for various architectures, rather than the x86-64 hardcoded # list above. def _parse_syscall(line): parts = line.split() return (int(parts[0]), parts[1].strip()) try: # Skip the first line, which is a header. The rest of the lines are simply # SYSCALL_NUM\tSYSCALL_NAME pairs. out = subprocess.check_output(['ausyscall', '--dump'], stderr=subprocess.STDOUT) # remove the first line of expected output out = out.split(b'\n',1)[1] syscalls = dict(map(_parse_syscall, out.strip().split(b'\n'))) except Exception as e: if platform.machine() == "x86_64": pass else: raise Exception("ausyscall: command not found") def syscall_name(syscall_num): """Return the syscall name for the particular syscall number.""" return syscalls.get(syscall_num, b"[unknown: %d]" % syscall_num)