/* * RecordMySQLQuery Record MySQL queries by probing the alloc_query() function * in mysqld. For Linux, uses BCC, eBPF. Embedded C. * * Basic example of BCC and uprobes. * * Copyright (c) Facebook, Inc. * Licensed under the Apache License, Version 2.0 (the "License") */ #include #include #include #include #include #include "BPF.h" const std::string BPF_PROGRAM = R"( #include struct query_probe_t { uint64_t ts; pid_t pid; char query[100]; }; BPF_HASH(queries, struct query_probe_t, int); int probe_mysql_query(struct pt_regs *ctx, void* thd, char* query, size_t len) { if (query) { struct query_probe_t key = {}; key.ts = bpf_ktime_get_ns(); key.pid = bpf_get_current_pid_tgid(); bpf_probe_read_user_str(&key.query, sizeof(key.query), query); int one = 1; queries.update(&key, &one); } return 0; } )"; const std::string ALLOC_QUERY_FUNC = "_Z11alloc_queryP3THDPKcj"; // Define the same struct to use in user space. struct query_probe_t { uint64_t ts; pid_t pid; char query[100]; }; int main(int argc, char** argv) { if (argc < 2) { std::cout << "USAGE: RecordMySQLQuery PATH_TO_MYSQLD [duration]" << std::endl; exit(1); } std::string mysql_path(argv[1]); std::cout << "Using mysqld path: " << mysql_path << std::endl; ebpf::BPF bpf; auto init_res = bpf.init(BPF_PROGRAM); if (!init_res.ok()) { std::cerr << init_res.msg() << std::endl; return 1; } auto attach_res = bpf.attach_uprobe(mysql_path, ALLOC_QUERY_FUNC, "probe_mysql_query"); if (!attach_res.ok()) { std::cerr << attach_res.msg() << std::endl; return 1; } int probe_time = 10; if (argc >= 3) probe_time = atoi(argv[2]); std::cout << "Probing for " << probe_time << " seconds" << std::endl; sleep(probe_time); auto table_handle = bpf.get_hash_table("queries"); auto table = table_handle.get_table_offline(); std::sort( table.begin(), table.end(), [](std::pair a, std::pair b) { return a.first.ts < b.first.ts; }); std::cout << table.size() << " queries recorded:" << std::endl; for (auto it : table) { std::cout << "Time: " << it.first.ts << " PID: " << it.first.pid << " Query: " << it.first.query << std::endl; } auto detach_res = bpf.detach_uprobe(mysql_path, ALLOC_QUERY_FUNC); if (!detach_res.ok()) { std::cerr << detach_res.msg() << std::endl; return 1; } return 0; }