def gen_prog(self): for lang, _ in self.config.items(): c = self.config[lang] if lang == 'DEFAULT': continue pids = [ int(n) for n in check_output( ["pidof", "-s", c['proccess_name_or_path']]).split() ] self.process.append({lang: pids}) usdts = [] for pid in pids: program = self.render( prog=c['prog'], pid=pid, read_class=c['read_class'], read_method=c['read_method'], ) usdt = USDT(pid=pid) usdt.enable_probe_or_bail(c['entry_probe'], 'trace_entry') usdt.enable_probe_or_bail(c['return_probe'], 'trace_return') usdts.append(usdt) if len(usdts) > 0: self.attached_bpf.append( {lang: BPF(text=program, usdt_contexts=usdts)})
def generate(self, pids): for probe_name, func_name in self.probes: for pid in pids: usdt = USDT(pid=pid) usdt.enable_probe_or_bail(probe_name, func_name) self.usdt_tab.append(usdt) return "".join(self.txt)
def __init__(self, usdt_name, pids, *args, **kwargs): # TODO(javierhonduco): Check what happens if we call this more than once on the same # Ruby binary for pid in pids: usdt = USDT(pid=pid) usdt.enable_probe_or_bail(usdt_name, self.BPF_FUNCTION_NAME.decode()) self.usdt_contexts.append(usdt) super().__init__(pids, *args, **kwargs)
BPF_PERF_OUTPUT(threads); int trace_pthread(struct pt_regs *ctx) { struct thread_event_t te = {}; u64 start_routine = 0; char type[] = "pthread"; te.native_id = bpf_get_current_pid_tgid() & 0xFFFFFFFF; bpf_usdt_readarg(2, ctx, &start_routine); te.runtime_id = start_routine; // This is really a function pointer __builtin_memcpy(&te.type, type, sizeof(te.type)); threads.perf_submit(ctx, &te, sizeof(te)); return 0; } """ usdt.enable_probe_or_bail("pthread_start", "trace_pthread") if args.language == "java": template = """ int %s(struct pt_regs *ctx) { char type[] = "%s"; struct thread_event_t te = {}; u64 nameptr = 0, id = 0, native_id = 0; bpf_usdt_readarg(1, ctx, &nameptr); bpf_usdt_readarg(3, ctx, &id); bpf_usdt_readarg(4, ctx, &native_id); bpf_probe_read(&te.name, sizeof(te.name), (void *)nameptr); te.runtime_id = id; te.native_id = native_id; __builtin_memcpy(&te.type, type, sizeof(te.type)); threads.perf_submit(ctx, &te, sizeof(te));
} sysentry.delete(&pid); return 0; } #endif // LATENCY #endif // SYSCALLS """.replace("READ_CLASS", read_class) \ .replace("READ_METHOD", read_method) \ .replace("PID_FILTER", "if ((pid >> 32) != %d) { return 0; }" % args.pid) \ .replace("DEFINE_NOLANG", "#define NOLANG" if not language else "") \ .replace("DEFINE_LATENCY", "#define LATENCY" if args.latency else "") \ .replace("DEFINE_SYSCALLS", "#define SYSCALLS" if args.syscalls else "") if language: usdt = USDT(pid=args.pid) usdt.enable_probe_or_bail(entry_probe, "trace_entry") if args.latency: usdt.enable_probe_or_bail(return_probe, "trace_return") else: usdt = None if args.ebpf or args.verbose: if args.verbose and usdt: print(usdt.get_text()) print(program) if args.ebpf: exit() bpf = BPF(text=program, usdt_contexts=[usdt] if usdt else []) if args.syscalls: print("Attached kernel tracepoints for syscall tracing.")
def randomword(length): letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(length)) randprefix = randomword(4) parser = argparse.ArgumentParser( description="Trace quic events", formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("pid", type=int, help="pid to attach to") args = parser.parse_args() usdt = USDT(pid=args.pid) usdt.enable_probe_or_bail("packet_acked", "on_packet_acked") usdt.enable_probe_or_bail("packet_sent", "on_packet_sent") usdt.enable_probe("packets_lost", "on_packets_lost") usdt.enable_probe("packet_recvd", "on_packet_recvd") usdt.enable_probe("rto_alarm", "on_rto_alarm") usdt.enable_probe("tlp_alarm", "on_tlp_alarm") usdt.enable_probe("handshake_alarm", "on_handshake_alarm") usdt.enable_probe("rto_verified", "on_rto_verified") #usdt.enable_probe("packet_clone", "on_packet_clone") usdt.enable_probe("packet_drop", "on_packet_drop") usdt.enable_probe("conn_close", "on_close") usdt.enable_probe("recvd_close", "on_recvd_close") usdt.enable_probe("cubic_ack", "on_cubic_ack") usdt.enable_probe("cubic_steady_cwnd", "on_cubic_steady_cwnd_changed") usdt.enable_probe("pacing_update", "on_pacing_update") try:
info->total_ns += bpf_ktime_get_ns() - e->timestamp; sysentry.delete(&pid); return 0; } #endif // LATENCY #endif // SYSCALLS """.replace("READ_CLASS", read_class) \ .replace("READ_METHOD", read_method) \ .replace("PID_FILTER", "if ((pid >> 32) != %d) { return 0; }" % args.pid) \ .replace("DEFINE_NOLANG", "#define NOLANG" if not language else "") \ .replace("DEFINE_LATENCY", "#define LATENCY" if args.latency else "") \ .replace("DEFINE_SYSCALLS", "#define SYSCALLS" if args.syscalls else "") if language: usdt = USDT(pid=args.pid) usdt.enable_probe_or_bail(entry_probe, "trace_entry") if args.latency: usdt.enable_probe_or_bail(return_probe, "trace_return") else: usdt = None if args.ebpf or args.verbose: if args.verbose and usdt: print(usdt.get_text()) print(program) if args.ebpf: exit() bpf = BPF(text=program, usdt_contexts=[usdt] if usdt else []) if args.syscalls: syscall_regex = "^[Ss]y[Ss]_.*"
int alloc_entry(struct pt_regs *ctx) { struct key_t key = {}; struct val_t *valp, zero = {}; u64 classptr = 0, size = 0; bpf_usdt_readarg(2, ctx, &classptr); bpf_usdt_readarg(4, ctx, &size); bpf_probe_read_user(&key.name, sizeof(key.name), (void *)classptr); valp = allocs.lookup_or_try_init(&key, &zero); if (valp) { valp->total_size += size; valp->num_allocs += 1; } return 0; } """ usdt.enable_probe_or_bail("object__alloc", "alloc_entry") # # Ruby # elif language == "ruby": create_template = """ int THETHING_alloc_entry(struct pt_regs *ctx) { struct key_t key = { .name = "THETHING" }; struct val_t *valp, zero = {}; u64 size = 0; bpf_usdt_readarg(1, ctx, &size); valp = allocs.lookup_or_try_init(&key, &zero); if (valp) { valp->total_size += size; valp->num_allocs += 1; }
BPF_PERF_OUTPUT(threads); int trace_pthread(struct pt_regs *ctx) { struct thread_event_t te = {}; u64 start_routine = 0; char type[] = "pthread"; te.native_id = bpf_get_current_pid_tgid() & 0xFFFFFFFF; bpf_usdt_readarg(2, ctx, &start_routine); te.runtime_id = start_routine; // This is really a function pointer __builtin_memcpy(&te.type, type, sizeof(te.type)); threads.perf_submit(ctx, &te, sizeof(te)); return 0; } """ usdt.enable_probe_or_bail("pthread_start", "trace_pthread") language = args.language if not language: language = utils.detect_language(languages, args.pid) if language == "java": template = """ int %s(struct pt_regs *ctx) { char type[] = "%s"; struct thread_event_t te = {}; u64 nameptr = 0, id = 0, native_id = 0; bpf_usdt_readarg(1, ctx, &nameptr); bpf_usdt_readarg(3, ctx, &id); bpf_usdt_readarg(4, ctx, &native_id); bpf_probe_read(&te.name, sizeof(te.name), (void *)nameptr);
if language == "java": program += """ int alloc_entry(struct pt_regs *ctx) { struct key_t key = {}; struct val_t *valp, zero = {}; u64 classptr = 0, size = 0; bpf_usdt_readarg(2, ctx, &classptr); bpf_usdt_readarg(4, ctx, &size); bpf_probe_read(&key.name, sizeof(key.name), (void *)classptr); valp = allocs.lookup_or_init(&key, &zero); valp->total_size += size; valp->num_allocs += 1; return 0; } """ usdt.enable_probe_or_bail("object__alloc", "alloc_entry") # # Ruby # elif language == "ruby": create_template = """ int THETHING_alloc_entry(struct pt_regs *ctx) { struct key_t key = { .name = "THETHING" }; struct val_t *valp, zero = {}; u64 size = 0; bpf_usdt_readarg(1, ctx, &size); valp = allocs.lookup_or_init(&key, &zero); valp->total_size += size; valp->num_allocs += 1; return 0; }