主ã«9æã«éãããæKaigiã®é¢ä¿ã¨ããè²ã ããããCè¨èªä»¥å¤ã®è¨èªã§BPFãã¤ããªãä½ããã¨ãã§ããªãã模索ãã¦ãã¾ã*1ãæSlackãªã©ã§ç¸è«ããã¦ããã£ã¦ãã¾ããããããªæãï¼è³æå¾åï¼ã
ãã®äºå調æ»ã¨ãã¦ãBPFãã¤ããªã¨ãã¦libbpfãåãæ±ããELFå½¢å¼ã®ãã¤ããªãã©ã®ãããªãã®ã調ã¹ã¦ãã¾ãã
ããããªããããã¥ã¡ã³ãããããããªæ°ãããã§ããªãã§ãããã¾ãã¼ãèªèº«ELFå½¢å¼ã«è©³ãããªããã¨ãããå®éã®ãã¡ã¤ã«ãçºããªãã調ã¹ãçµæ*2ãæ®ãã¨ããã¨æãã¾ãã
ååã®è¨äºã§å©ç¨ãããcgroup v2ã®ããã¤ã¹ãã£ã«ã¿ã«å©ç¨ããBPFããã°ã©ã ãã
以ä¸ã®ã³ãã³ãã§ãã«ããã¾ãã
$ clang -O1 -c -target bpf dev_cgroup.c -o dev_cgroup.o
ã¾ã㯠dev_cgroup.o
ã® readelf -a
ã®çµæãçºãã¦ã¿ã¾ãã
$ readelf -a src/dev_cgroup.o ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Linux BPF Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 368 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 64 (bytes) Number of section headers: 7 Section header string table index: 1
Type: REL
㧠Machine: Linux BPF
ã¨è¡¨ç¤ºããã¾ããã¾ããããã°ã©ã ãããã¯ããã¾ãããã»ã¯ã·ã§ã³ããããçºãã¾ãã
Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .strtab STRTAB 0000000000000000 00000112 000000000000005e 0000000000000000 0 0 1 [ 2] .text PROGBITS 0000000000000000 00000040 0000000000000000 0000000000000000 AX 0 0 4 [ 3] cgroup/dev PROGBITS 0000000000000000 00000040 0000000000000038 0000000000000000 AX 0 0 8 [ 4] license PROGBITS 0000000000000000 00000078 0000000000000004 0000000000000000 WA 0 0 1 [ 5] .llvm_addrsig LOOS+0xfff4c03 0000000000000000 00000110 0000000000000002 0000000000000000 E 6 0 1 [ 6] .symtab SYMTAB 0000000000000000 00000080 0000000000000090 0000000000000018 1 4 8 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), p (processor specific)
ã»ã¯ã·ã§ã³ã¯ãããªã«å¤ãããã¾ããã llvm-objdump -x
ã®çµæã¨ãæ¯è¼ã
Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000000 0000000000000000 0000000000000000 00000040 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 cgroup/dev 00000038 0000000000000000 0000000000000000 00000040 2**3 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 license 00000004 0000000000000000 0000000000000000 00000078 2**0 CONTENTS, ALLOC, LOAD, DATA 3 .llvm_addrsig 00000002 0000000000000000 0000000000000000 00000110 2**0 CONTENTS, READONLY, EXCLUDE
ã·ã³ãã«ãã¼ãã«ã¯ããã§ãã
Symbol table '.symtab' contains 6 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS dev_cgroup.c 2: 0000000000000028 0 NOTYPE LOCAL DEFAULT 3 LBB0_2 3: 0000000000000030 0 NOTYPE LOCAL DEFAULT 3 LBB0_3 4: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 _license 5: 0000000000000000 56 FUNC GLOBAL DEFAULT 3 bpf_prog1
ã»ã¯ã·ã§ã³ãããããä½è
ãªã®ãï¼ ã¨ããã¨ããããã .strtab
ããããã¾ãã
ä½è ãªã®ããèªã¿è¾¼ãåã«ELFãã¡ã¤ã«ã®ãã£ããããã¬ã¤ã¢ã¦ããé ã«å ¥ãã¦ããã¨ããã§ãããã以ä¸ã¯ãSolarisã®ããã¥ã¢ã«ã®å¼ç¨ã§ãã
ELFãããã¼ãã»ã¯ã·ã§ã³ãããã¼ï¼ãã¼ãã«ï¼ã®ã¨ããã«ã¯ãå ·ä½çã«ã¯ãããã対å¿ããæ§é ä½ï¼Elf32|64_Ehdr æ§é ä½ãElf32|64_Shdr æ§é ä½ï¼ã®ãã¤ããªè¡¨ç¾ãæ ¼ç´ããã¦ãã¾ããã»ã¯ã·ã§ã³ãããã¼ããã¼ãã«ãã®ç®æã¯Elf*_Shdræ§é ä½ã®é åã§ããã
ãã®ä¸ã§ä»åãRubyã® rbelftools ã¨ããgemãè£å©çã«ç¨ãã¦ããã¡ã¤ã«ããã¼ã¹ãã¦ããããã®ã»ã¯ã·ã§ã³æ§é ä½ã®å¤ã«ä½ãå ¥ããåå¾ãã¦ãã¾ãããããè¦ãªããé²ãã¾ããã¡ãªã¿ã«ã»ã¯ã·ã§ã³0ã«ã¯å¿ ãNullSectionãã¼ãåããå ¥ããããªã®ã§ã¹ããããã¾ãã
f = File.open 'src/dev_cgroup.o' elf = ELFTools::ELFFile.new f #=> #<ELFTools::ELFFile:0x000055782f67d098 @elf_class=64, # @endian=:little, @stream=#<File:src/dev_cgroup.o>> elf.sections[0] #=> #<ELFTools::Sections::NullSection:0x000055782fed00b0 @header= {:sh_name=>0, :sh_type=>0, :sh_flags=>0, :sh_addr=>0, :sh_offset=>0, :sh_size=>0, :sh_link=>0, :sh_info=>0, :sh_addralign=>0, :sh_entsize=>0}, ...> elf.sections[1] #=> #<ELFTools::Sections::StrTabSection:0x000055782ff23e18 @header= {:sh_name=>54, :sh_type=>3, :sh_flags=>0, :sh_addr=>0, :sh_offset=>274, :sh_size=>94, :sh_link=>0, :sh_info=>0, :sh_addralign=>1, :sh_entsize=>0}, ...>
ããã§ãsh_offset ã¯ãã¡ã¤ã«å ¨ä½ã®ãªãã»ããã sh_size ã¯ã»ã¯ã·ã§ã³é åã®ãµã¤ãºã§ãï¼readelf/objdumpã®ã©ã®é ç®ã«å¯¾å¿ããã確èªããªããé²ãã¾ãããï¼ããã¼ã¿ã®ã¢ã©ã¤ã¡ã³ã sh_addralign ã¯1ãã¤ãåä½ã§ãã
"%08x" % 274 #=> "00000112" 94.divmod 16 # sh_size #=> [5, 14]
hexdump -C
ã§ãã¤ããªãåå¾ãã対å¿ããç®æã確èªãã¾ãããã
èæ¯ã赤ãããã .cgroup/dev\0...bpf_prog1\0
ã®ç®æãã¾ãã«BPFããã°ã©ã ã§ãã
ã§ã¯ååã¯ã©ããã£ã¦åå¾ãã¦ãããï¼ sh_name
ã®é
ç®ã«æ³¨ç®ããã¨ã
54.divmod 16 #=> [3, 6]
ãã®ã¨ãã .strtab
ã®å
é ãã54ãã¤ãé²ãã ç®æãä¸å³ã®éèæ¯ã§ä¸ç·ãæ¯ã£ãç®æ ã« .strtab
èªä½ã®ååãåãè¾¼ã¾ãã¦ãã¾ãã
ããªãã¡ .strtab
ã«ã¯ãã»ã¯ã·ã§ã³ã®ååãªã©ELFãã¡ã¤ã«ã®å
é¨ã§ä½¿ãæååã®ãã¼ãã«ãã¾ã¨ãã¦å
¥ã£ã¦ããã¨ãããã¨ããããã¾ããå¾è¿°ãã .symtab
ã§ã¯ãã·ã³ãã«ã®ååã«ã使ããã¾ãã
ãªããstrtabã»ã¯ã·ã§ã³ã®ä½ç½®ï¼ã¤ã³ããã¯ã¹ãä»å㯠1
ï¼ããELFãããæ§é ä½ã® e_shstrndx
ã¡ã³ãã§æå®ããå¿
è¦ãããã¾ã*3ãreadelfã®çµæã§è¨ã Section header string table index
ã®ã¨ããã§ãã
elf.header #=> {:e_ident=> {:magic=>"\x7FELF", :ei_class=>2, :ei_data=>1, :ei_version=>1, :ei_osabi=>0, :ei_abiversion=>0, :ei_padding=>"\x00\x00\x00\x00\x00\x00\x00"}, :e_type=>1, # :e_machine=>247, :e_version=>1, :e_entry=>0, :e_phoff=>0, :e_shoff=>368, :e_flags=>0, :e_ehsize=>64, :e_phentsize=>0, :e_phnum=>0, :e_shentsize=>64, :e_shnum=>7, :e_shstrndx=>1}
strtabã»ã¯ã·ã§ã³ãèªåã§å®ç¾©ããéã¯ä»¥ä¸ã«æ°ãã¤ãããã¨è¨ããã¨ã«ãªãã¾ãã
- e_shstrndx ãæ£ãããã
.strtab
ã¨ããã»ã¯ã·ã§ã³ãä½ã- sh_name ã®ä½ç½®ãæ£ãã
- sh_type=3 (
SHT_STRTAB
)
- strtabç¨ã®ãã¼ã¿ãé©åã«é ç½®ããã
æ®ãã®ã»ã¯ã·ã§ã³ããããé§ã足ã§çºãã¾ãã
elf.sections[2] => #<ELFTools::Sections::Section:0x0000557577a50540 @header= {:sh_name=>12, :sh_type=>1, # SHT_PROGBITS :sh_flags=>6, # :sh_addr=>0, :sh_offset=>64, # "00000040" :sh_size=>0, :sh_link=>0, :sh_info=>0, :sh_addralign=>4, :sh_entsize=>0}, ...> elf.sections[2].name => ".text" elf.sections[2].data => ""
.text
ã»ã¯ã·ã§ã³ãä¸å¿å®ç¾©ããã¦ãã¾ããããsizeãã¼ãã§ãããã¿ãã¬ã«ãªãã¾ããã試ããçµæã¨ãã¦ã¯å®ã¯ãã®ã»ã¯ã·ã§ã³ã¯ãªãã¦ãããã§ãã
elf.sections[3] => #<ELFTools::Sections::Section:0x0000557577a43908 @header= {:sh_name=>1, :sh_type=>1, # SHT_PROGBITS :sh_flags=>6, # SHF_ALLOC|SHF_EXECINSTR :sh_addr=>0, :sh_offset=>64, :sh_size=>56, :sh_link=>0, :sh_info=>0, :sh_addralign=>8, :sh_entsize=>0}, elf.sections[3].name => "cgroup/dev" elf.sections[3].data => "a\x12\x04\x00\x00\x00\x00\x00U\x02\x03\x00..."
BPFã®Cã³ã¼ãã§æå®ãã¦ãã "cgroup/dev"
ã»ã¯ã·ã§ã³ã§ããã¼ã¿ã¨ãã¦eBPFã®ãªãã³ã¼ããè©°ã¾ã£ã¦ãã¾ããã¢ã©ã¤ã¡ã³ããeBPFã®åºæ¬çãªå½ä»¤é·ã§ãã8ãã¤ãã§ãã
elf.sections[4] => #<ELFTools::Sections::Section:0x0000563780cf7458 @header= {:sh_name=>33, :sh_type=>1, # SHT_PROGBITS :sh_flags=>3, # SHF_WRITE|SHF_ALLOC :sh_addr=>0, :sh_offset=>120, #=> 00000078 :sh_size=>4, :sh_link=>0, :sh_info=>0, :sh_addralign=>1, :sh_entsize=>0},
ã©ã¤ã»ã³ã¹ã®æ å ±ã§ããGPLãåã¾ã£ã¦ããæ§åã
.llvm_addrsig ã¨ããã»ã¯ã·ã§ã³ã¯çµå±å½¹å²ãä¸æã§ãããsh_typeã以ä¸ã®ç¯å²ãªã®ã§OSåºæã®è¨å®ã®ããã§ãããBPFããã°ã©ã ã«å«ã¾ãã¦ããªãã¦ãåé¡ãªãããã§ãã
#define SHT_LOOS 0x60000000 #define SHT_HIOS 0x6fffffff
symtabã®æ§é ãè¦ã¦ã¿ã¾ããã»ã¯ã·ã§ã³ã¯ä»¥ä¸ã®ããã«ãªã£ã¦ãã¾ãã
elf.sections[6] => #<ELFTools::Sections::SymTabSection:0x0000563780db7988 @header= {:sh_name=>62, :sh_type=>2, :sh_flags=>0, :sh_addr=>0, :sh_offset=>128, # 00000080 :sh_size=>144, # = 9 * 16 + 0 = 24 * 6 :sh_link=>1, # https://docs.oracle.com/cd/E19253-01/819-0391/6n2qq2n73/index.html#chapter6-47976 # é¢é£ä»ãããã¦ããæååãã¼ãã«ã® # ã»ã¯ã·ã§ã³ãããã¼ã¤ã³ããã¯ã¹ã :sh_info=>4, # ã·ã³ãã«ãã¼ãã«ã»ã¯ã·ã§ã³ã® # sh_info ã»ã¯ã·ã§ã³ãããã¼ã¡ã³ãã¼ã¯ã # æåã®*ãã¼ã«ã«ã§ã¯ãªã*ã·ã³ãã«ã«å¯¾ãã # ã·ã³ãã«ãã¼ãã«ã¤ã³ããã¯ã¹ãä¿æ :sh_addralign=>8, :sh_entsize=>24}, @name=".symtab", ... >
ãã¼ã¿ã¯ãã¤ããªã§ã¯ãã®ä½ç½®ã§ãã
ãã®ãã¤ããªé¨åã«ã¯ãsh_entsize
ï¼=24ï¼ãã¤ãã®æ§é ä½ã sh_size/sh_entsize
ï¼=144/24 = 6ï¼å並ãã§ãã¾ããobjdumpã®ãã¤ããªã¯8ãã¤ãã§åºåããã¦ããã®ã§ãã®3ã¤åã§çºãã¾ãã
ãã®æ§é ä½ã¯ããè¨ãã¬ã¤ã¢ã¦ãããã¦ãã¾ãã
typedef struct { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym;
ä¸ã¤ç®ã¯ç¸å¤ãããã¼ãåããªã®ã§ãäºã¤ç®ããã¿ã¦ã¿ãã
elf.sections[6].symbols[1] => #<ELFTools::Sections::Symbol:0x0000563780cfebe0 @header= {:st_name=>41, :st_info=>4, :st_other=>0, :st_shndx=>65521, :st_value=>0, :st_size=>0}, # ... #define STT_FILE 4 @name="dev_cgroup.c", @stream=#<File:dev_cgroup.o>,...
以ä¸ã¯ llvm-objdump -s
ã§ã®è¡¨ç¤ºã§ãï¼0çªå°å§ã¾ãã«ããããï¼ãã赤èæ¯ã«å¯¾å¿ãã¦ãã¾ããã
ã·ã³ãã«ã®åå st_name
ã¯ãç¸å¤ãããstrtabããå¼ãã¦ãã¾ããã·ã³ãã«åã®ãã¼ãã«ã«ä½¿ãstrtabã®ã¤ã³ããã¯ã¹ã¨ãã¦ã»ã¯ã·ã§ã³ãããã® sh_link = 1
ã使ããã¦ãã¾ããå¥ã
ã®strtabã«ãããã¨ãå¯è½ãªã®ã§ãããã
41 = 2 * 16 + 9
ã§ãã
:st_shndx=>65521 = 0xfff1
ã¯å®æ° SHN_ABS
ã§ããçµå±ãã®ã·ã³ãã«ã¯ã½ã¼ã¹ãã¡ã¤ã«åã§ããã
ä»ã®ã·ã³ãã«ãè¦ã¦ã¿ã¾ãï¼ä¸é¨çç¥ï¼ãå ã«ã©ã¤ã»ã³ã¹ã¨ããã°ã©ã ããã
elf.sections[6].symbols[4] => #<ELFTools::Sections::Symbol:0x0000563780cd2b80 @header={:st_name=>32, :st_info=>17, :st_other=>0, :st_shndx=>4, :st_value=>0, :st_size=>4}, @name="_license",... > elf.sections[6].symbols[5] => #<ELFTools::Sections::Symbol:0x0000563780ca5d60 @header={:st_name=>84, :st_info=>18, :st_other=>0, :st_shndx=>3, :st_value=>0, :st_size=>56}, @name="bpf_prog1", ...>
17 = STB_GLOBAL<<4|STT_OBJECT
, 18 = STB_GLOBAL<<4|STT_FUNC
ã§ãã
// elf.h #define STB_LOCAL 0 #define STB_GLOBAL 1 #define STB_WEAK 2 #define STT_NOTYPE 0 #define STT_OBJECT 1 #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 #define STT_COMMON 5 #define STT_TLS 6 #define ELF_ST_BIND(x) ((x) >> 4) #define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
ã§ãst_shndxã¯ã»ã¯ã·ã§ã³ã§ã®indexãst_sizeãã»ã¯ã·ã§ã³å´ã®sh_sizeã«å¯¾å¿ãã¦ãã¾ããã§ãst_value = 0 ãªã®ã§ããã¨ãã° bpf_prog1
ãªãsections[3]ã®ãã¼ã¿ã®é ãããã¨ãªãæãã§ãã
æ®ãã¯ã¬ã¼ãã«ã§ããã
elf.sections[6].symbols[2] #=> #<ELFTools::Sections::Symbol:0x0000563780ce6d38 @header={:st_name=>77, :st_info=>0, :st_other=>0, :st_shndx=>3, :st_value=>40, :st_size=>0}, @name="LBB0_2",
sections[3] ã® 40(= 00000028)
ãã¤ãç®ã¯ä½ãã¨ããã¨ã
ã¨ãããã¨ã§ã llvm-objdump -d
ãªã©ã§ã¬ã¼ãã«ã®æ
å ±ã表示ããã¾ãã
ãã£ã¹ã¢ã»ã³ãã«ããéã«ã¯ä¾¿å©ã§ããããã®ã¬ã¼ãã«ã®æ å ±ãå®ã¯BPFãã¤ããªã¨ãã¦ã¯å¿ é ã§ã¯ãªãããã§ãã
ããã¾ã§ãã¾ã¨ããã¨
- å¿
è¦ãªã»ã¯ã·ã§ã³
- strtab
- BPFããã°ã©ã ã»ã¯ã·ã§ã³ with æ£ããåå
- ã©ã¤ã»ã³ã¹
- symtab
- å¿
è¦ãªã·ã³ãã«ãã¼ãã«
- BPFããã°ã©ã ã®é¢æ°å
- ã©ã¤ã»ã³ã¹ã®å ´æ
ãæä½ã®æä½éãã®ããã§ãããã®ä¸ã§BPFããã°ã©ã ã»ã¯ã·ã§ã³ã«ããã³ãã¢ã»ã³ãã«ããBPFããã°ã©ã ã§ãåãè¾¼ãã°ãåãã¯ãã
ããã¾ã§ã§é·ããªã£ãã®ã§æ¬¡åãå®éã«ããã°ã©ã ãã¦ã¿ã¾ãã
*1:Rustãªãredbpfã¨ãããã®ãããã¾ãããµã³ãã«è¦ãã¨ã¯ã½ãã£ããã: https://github.com/foniod/redbpf/blob/main/examples/example-probes/src/vfsreadlat/main.rs
*2:調ã¹ãããã»ã¹èªä½ãæ®ããã¨ã¯ãå¾å¦ã®ããã«ãæªããªãã§ããã
*3:追è¨ï¼2021/08/31ï¼: æ®éã®å®è¡ãã¡ã¤ã«ã¯ ã»ã¯ã·ã§ã³ãããã®åå㯠.shstrtab ã¨ããååã®SHT_STRTABãªã»ã¯ã·ã§ã³ãåç §ããããã§ãããBPFã®ãªãã¸ã§ã¯ãã¯.shstrtabã¯ä½ãããï¼å°ãªãã¨ãclang -target bpf ã§ã¯ã¤ããããï¼ã.strtab ã»ã¯ã·ã§ã³ã«ã»ã¯ã·ã§ã³åãã·ã³ãã«å両æ¹ã®æååãæ ¼ç´ããã¾ãã