1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
from __future__ import print_function from bcc import BPF import argparse import ctypes as ct import sys,time import subprocess
bpf_text = """ #include <uapi/linux/ptrace.h> /**************************mysql struct def start*****************************/ enum enum_server_command { COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON, COM_BINLOG_DUMP_GTID, COM_RESET_CONNECTION, /* don't forget to update const char *command_name[] in sql_parse.cc */ /* Must be last */ COM_END };
typedef struct st_com_init_db_data { const char *db_name; unsigned long length; } COM_INIT_DB_DATA;
#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) #define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) #define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) #define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3)
#define LOCK_MODE_MASK 0xFUL #define LOCK_TYPE_MASK 0xF0UL
enum mysql_enum_shutdown_level { SHUTDOWN_DEFAULT = 0, SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, KILL_QUERY= 254, KILL_CONNECTION= 255 };
typedef struct st_com_refresh_data { unsigned char options; } COM_REFRESH_DATA;
typedef struct st_com_shutdown_data { enum mysql_enum_shutdown_level level; } COM_SHUTDOWN_DATA;
typedef struct st_com_kill_data { unsigned long id; } COM_KILL_DATA;
typedef struct st_com_set_option_data { unsigned int opt_command; } COM_SET_OPTION_DATA;
typedef struct st_com_stmt_execute_data { unsigned long stmt_id; unsigned long flags; unsigned char *params; unsigned long params_length; } COM_STMT_EXECUTE_DATA;
typedef struct st_com_stmt_fetch_data { unsigned long stmt_id; unsigned long num_rows; } COM_STMT_FETCH_DATA;
typedef struct st_com_stmt_send_long_data_data { unsigned long stmt_id; unsigned int param_number; unsigned char *longdata; unsigned long length; } COM_STMT_SEND_LONG_DATA_DATA;
typedef struct st_com_stmt_prepare_data { const char *query; unsigned int length; } COM_STMT_PREPARE_DATA;
typedef struct st_stmt_close_data { unsigned int stmt_id; } COM_STMT_CLOSE_DATA;
typedef struct st_com_stmt_reset_data { unsigned int stmt_id; } COM_STMT_RESET_DATA;
typedef struct st_com_query_data { const char *query; unsigned int length; } COM_QUERY_DATA;
typedef struct st_com_field_list_data { unsigned char *table_name; unsigned int table_name_length; const unsigned char *query; unsigned int query_length; } COM_FIELD_LIST_DATA;
union COM_DATA {
COM_INIT_DB_DATA com_init_db; COM_REFRESH_DATA com_refresh; COM_SHUTDOWN_DATA com_shutdown; COM_KILL_DATA com_kill; COM_SET_OPTION_DATA com_set_option; COM_STMT_EXECUTE_DATA com_stmt_execute; COM_STMT_FETCH_DATA com_stmt_fetch; COM_STMT_SEND_LONG_DATA_DATA com_stmt_send_long_data; COM_STMT_PREPARE_DATA com_stmt_prepare; COM_STMT_CLOSE_DATA com_stmt_close; COM_STMT_RESET_DATA com_stmt_reset; COM_QUERY_DATA com_query; COM_FIELD_LIST_DATA com_field_list; };
struct String { char *m_ptr; size_t m_length; void *m_charset; u32 m_alloced_length; bool m_is_alloced; }; /**************************mysql struct def end*****************************/
typedef struct perf_event{ u32 tid; u32 size; u64 ts; char user[16]; char ip[16]; char host[24]; char sql[256]; }COM_PERF_EVENT;
BPF_HASH(tid_dispatch_map, u32, COM_PERF_EVENT);
BPF_PERF_OUTPUT(events);
static inline void* GET_SC_CTX_PTR_FROM_THD_PTR(void* thd) {return *(void**)(thd + 0x1198);} static inline void* GET_USER_PTR_FROM_SC_CTX_PTR(void* thd) {return thd + 0xa0;} static inline void* GET_HOST_PTR_FROM_SC_CTX_PTR(void* thd) {return thd + 0x20;} static inline void* GET_IP_PTR_FROM_SC_CTX_PTR(void* thd) {return thd + 0x40;}
int dispatch_command_entry(struct pt_regs *ctx) {
enum enum_server_command command_id = PT_REGS_PARM3(ctx); if (command_id != COM_QUERY) return 0;
COM_PERF_EVENT event = {}; event.tid = bpf_get_current_pid_tgid();
union COM_DATA *com_data = (union COM_DATA *)PT_REGS_PARM2(ctx); event.size = com_data->com_query.length; bpf_probe_read_str(&event.sql, sizeof(event.sql), com_data->com_query.query);
void *thd = (void*) PT_REGS_PARM1(ctx);
void *sc_ctx = GET_SC_CTX_PTR_FROM_THD_PTR(thd); //user char *user = GET_USER_PTR_FROM_SC_CTX_PTR(sc_ctx); bpf_probe_read_str(&event.user, sizeof(event.user), user); //host struct String *host = (struct String *)GET_HOST_PTR_FROM_SC_CTX_PTR(sc_ctx); bpf_probe_read_str(&event.host, sizeof(event.host), host->m_ptr); //ip struct String *ip = (struct String *)GET_IP_PTR_FROM_SC_CTX_PTR(sc_ctx); bpf_probe_read_str(&event.ip, sizeof(event.ip), ip->m_ptr);
event.ts = bpf_ktime_get_ns();
//record dispatch tid_dispatch_map.insert(&event.tid,&event);
return 0; }
int dispatch_command_return(struct pt_regs *ctx) { u32 thread_id = bpf_get_current_pid_tgid(); COM_PERF_EVENT *event = tid_dispatch_map.lookup(&thread_id); if (!event) return 0; event->ts = bpf_ktime_get_ns() - event->ts; events.perf_submit(ctx, event, sizeof(*event)); tid_dispatch_map.delete(&thread_id); return 0; } """
b = BPF(text=bpf_text) b.attach_uprobe(name="/home/mysqld", sym="_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command",fn_name='dispatch_command_entry') b.attach_uretprobe(name="/home/mysqld", sym="_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command",fn_name='dispatch_command_return') def print_event(cpu, data, size): event = b["events"].event(data) print("%s %s %s %s %s %s %s" % (event.tid, event.ts, event.user, event.host, event.ip, event.sql, event.size)) b["events"].open_perf_buffer(print_event) print("thread_id time(ns) user host ip sql sql_size") while 1: try: b.perf_buffer_poll() except KeyboardInterrupt: exit()
|