diff --git a/ebpf/README.txt b/ebpf/README.txt new file mode 100644 index 0000000..90f782a --- /dev/null +++ b/ebpf/README.txt @@ -0,0 +1,5 @@ +eBPF experiments + +Installing requirements on a Debian-esque: + + sudo apt-get install python3-bpfcc diff --git a/ebpf/bpf.py b/ebpf/bpf.py new file mode 100755 index 0000000..6ef236f --- /dev/null +++ b/ebpf/bpf.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +import argparse +import sys + +from bcc import BPF + + +DEBUG_FLAGS = { + "ir": 0x1, # debug output compiled LLVM IR + "bpf": 0x2, # debug output loaded BPF bytecode and register state on branches. + "pp": 0x4, # debug output pre-processor result. + "src": 0x8, # debug output ASM instructions embedded with source. + "reg": 0x10, # debug output register state on all instructions in addition to DEBUG_BPF. + "btf": 0x20, # debug BTF +} + + +def get_debug_flags(args: str) -> int: + if not args.strip(): + return 0 + + flags = [arg.strip() for arg in args.split(",")] + debug = 0 + for flag in flags: + debug |= DEBUG_FLAGS[flag] + return debug + + +def load_program(debug_args: str, program_source: str) -> BPF: + debug_flags = get_debug_flags(debug_args) + + program: str + if program_source == "-": + print('LD: STDIN') + program = sys.stdin.read() + else: + print('LD: {}'.format(program_source)) + with open(program_source) as source_file: + program = source_file.read() + + bpf = BPF(text=program, debug=debug_flags) + print('LD: OK') + return bpf + + +def main(args): + bpf = load_program(args.debug, args.path) + print('RUN') + bpf.trace_print() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog="bpf", description="Run BPF programs") + parser.add_argument("--debug", "-d", help="debug flags", default="") + parser.add_argument("path", help="program source") + + args = parser.parse_args() + main(args) diff --git a/ebpf/hello.c b/ebpf/hello.c new file mode 100644 index 0000000..ce145d0 --- /dev/null +++ b/ebpf/hello.c @@ -0,0 +1,5 @@ +int kprobe__sys_clone(void *ctx) +{ + bpf_trace_printk("Hello, world\n"); + return 0; +} diff --git a/ebpf/hello.py b/ebpf/hello.py new file mode 100755 index 0000000..f9d7c90 --- /dev/null +++ b/ebpf/hello.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 + +from bcc import BPF + +program = """ +int +kprobe__sys_clone(void *ctx) +{ + bpf_trace_printk("Hello, world\\n"); + return 0; +} +""" + +print('LD PROG') +b = BPF(text=program) +print('TRC PRN') +b.trace_print() diff --git a/ebpf/hello2.c b/ebpf/hello2.c new file mode 100644 index 0000000..9ce0c52 --- /dev/null +++ b/ebpf/hello2.c @@ -0,0 +1,5 @@ +int kprobe__sys_read(void *ctx) +{ + bpf_trace_printk("Hello, world\n"); + return 0; +} diff --git a/ebpf/requirements.txt b/ebpf/requirements.txt new file mode 100644 index 0000000..d6556e0 --- /dev/null +++ b/ebpf/requirements.txt @@ -0,0 +1 @@ +bcc diff --git a/from_scratch/compiler.rb b/from_scratch/compiler.rb new file mode 100755 index 0000000..c65c18d --- /dev/null +++ b/from_scratch/compiler.rb @@ -0,0 +1,57 @@ +#!/usr/bin/env ruby + +# lexer(tokeniser)->parser->code generator + +class Tokenizer + TOKEN_TYPES = [ + [:def, /\bdef\b/], + [:end, /\bend\b/], + [:identifier, /\b[a-zA-Z]+\b/], + [:integer, /\b[0-9]+\b/], + [:oparen, /\(/], + [:cparen, /\)/], + ] + + def initialize(code) + @code = code + end + + def tokenize + tokens = [] + until @code.empty? + token = tokenize_one + tokens << token + @code = @code.strip + end + return tokens + end + + def tokenize_one + TOKEN_TYPES.each do |type, re| + re = /\A(#{re})/ + if @code =~ re + value = $1 + @code = @code[value.length..-1] + return Token.new(type, value) + end + end + end +end + +Token = Struct.new(:type, :value) + +# 11m30s +class Parser + def initialize(tokens) + @tokens = tokens + end + + def parse + end +end + + +tokens = Tokenizer.new(File.read("test.src")).tokenize +puts tokens.map(&:inspect).join("\n") +tree = Parser.new(tokens).parse +p tree diff --git a/from_scratch/test.src b/from_scratch/test.src new file mode 100644 index 0000000..8d7190e --- /dev/null +++ b/from_scratch/test.src @@ -0,0 +1,2 @@ +def f() 1 end + diff --git a/misc/oddity.py b/misc/oddity.py new file mode 100644 index 0000000..42f51a0 --- /dev/null +++ b/misc/oddity.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +# see https://www.solipsys.co.uk/new/PowersOfTwoInLexOrder.html?sg28hn +# compare some_stats(9) with some_stats(100). After 9, the standard +# deviation and variance start to rise quickly. + +import statistics + +def oddities(n): + ns = [] + for i in range(1, n+1): + v = 2 ** i + v = str(v) + ns.append(v) + ns.sort() + return [float(v[0] + '.' + v[1:]) for v in ns] + +def evenities(n): + ns = [] + for i in range(1, n+1): + v = 10 ** (i / 10.) + ns.append(v) + return ns + +def differences(n): + ons = oddities(n) + ens = evenities(n) + print(ons) + print(ens) + deltas = [abs(ens[i] - ons[i]) for i in range(len(ons))] + return deltas + + + +def some_stats(n): + deltas = differences(n) + print('Min: {}'.format(min(deltas))) + print('Avg: {}'.format(sum(deltas) / len(deltas))) + print('Max: {}'.format(max(deltas))) + print(' Std dev: {}'.format(statistics.stdev(deltas))) + print('Variance: {}'.format(statistics.variance(deltas)))