1 /* 2 * db-export.c: Support for exporting data suitable for import to a database 3 * Copyright (c) 2014, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 */ 15 16 #include <errno.h> 17 18 #include "evsel.h" 19 #include "machine.h" 20 #include "thread.h" 21 #include "comm.h" 22 #include "symbol.h" 23 #include "event.h" 24 #include "util.h" 25 #include "thread-stack.h" 26 #include "db-export.h" 27 28 struct deferred_export { 29 struct list_head node; 30 struct comm *comm; 31 }; 32 33 static int db_export__deferred(struct db_export *dbe) 34 { 35 struct deferred_export *de; 36 int err; 37 38 while (!list_empty(&dbe->deferred)) { 39 de = list_entry(dbe->deferred.next, struct deferred_export, 40 node); 41 err = dbe->export_comm(dbe, de->comm); 42 list_del(&de->node); 43 free(de); 44 if (err) 45 return err; 46 } 47 48 return 0; 49 } 50 51 static void db_export__free_deferred(struct db_export *dbe) 52 { 53 struct deferred_export *de; 54 55 while (!list_empty(&dbe->deferred)) { 56 de = list_entry(dbe->deferred.next, struct deferred_export, 57 node); 58 list_del(&de->node); 59 free(de); 60 } 61 } 62 63 static int db_export__defer_comm(struct db_export *dbe, struct comm *comm) 64 { 65 struct deferred_export *de; 66 67 de = zalloc(sizeof(struct deferred_export)); 68 if (!de) 69 return -ENOMEM; 70 71 de->comm = comm; 72 list_add_tail(&de->node, &dbe->deferred); 73 74 return 0; 75 } 76 77 int db_export__init(struct db_export *dbe) 78 { 79 memset(dbe, 0, sizeof(struct db_export)); 80 INIT_LIST_HEAD(&dbe->deferred); 81 return 0; 82 } 83 84 int db_export__flush(struct db_export *dbe) 85 { 86 return db_export__deferred(dbe); 87 } 88 89 void db_export__exit(struct db_export *dbe) 90 { 91 db_export__free_deferred(dbe); 92 call_return_processor__free(dbe->crp); 93 dbe->crp = NULL; 94 } 95 96 int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel) 97 { 98 if (evsel->db_id) 99 return 0; 100 101 evsel->db_id = ++dbe->evsel_last_db_id; 102 103 if (dbe->export_evsel) 104 return dbe->export_evsel(dbe, evsel); 105 106 return 0; 107 } 108 109 int db_export__machine(struct db_export *dbe, struct machine *machine) 110 { 111 if (machine->db_id) 112 return 0; 113 114 machine->db_id = ++dbe->machine_last_db_id; 115 116 if (dbe->export_machine) 117 return dbe->export_machine(dbe, machine); 118 119 return 0; 120 } 121 122 int db_export__thread(struct db_export *dbe, struct thread *thread, 123 struct machine *machine, struct comm *comm) 124 { 125 struct thread *main_thread; 126 u64 main_thread_db_id = 0; 127 int err; 128 129 if (thread->db_id) 130 return 0; 131 132 thread->db_id = ++dbe->thread_last_db_id; 133 134 if (thread->pid_ != -1) { 135 if (thread->pid_ == thread->tid) { 136 main_thread = thread; 137 } else { 138 main_thread = machine__findnew_thread(machine, 139 thread->pid_, 140 thread->pid_); 141 if (!main_thread) 142 return -ENOMEM; 143 err = db_export__thread(dbe, main_thread, machine, 144 comm); 145 if (err) 146 goto out_put; 147 if (comm) { 148 err = db_export__comm_thread(dbe, comm, thread); 149 if (err) 150 goto out_put; 151 } 152 } 153 main_thread_db_id = main_thread->db_id; 154 if (main_thread != thread) 155 thread__put(main_thread); 156 } 157 158 if (dbe->export_thread) 159 return dbe->export_thread(dbe, thread, main_thread_db_id, 160 machine); 161 162 return 0; 163 164 out_put: 165 thread__put(main_thread); 166 return err; 167 } 168 169 int db_export__comm(struct db_export *dbe, struct comm *comm, 170 struct thread *main_thread) 171 { 172 int err; 173 174 if (comm->db_id) 175 return 0; 176 177 comm->db_id = ++dbe->comm_last_db_id; 178 179 if (dbe->export_comm) { 180 if (main_thread->comm_set) 181 err = dbe->export_comm(dbe, comm); 182 else 183 err = db_export__defer_comm(dbe, comm); 184 if (err) 185 return err; 186 } 187 188 return db_export__comm_thread(dbe, comm, main_thread); 189 } 190 191 int db_export__comm_thread(struct db_export *dbe, struct comm *comm, 192 struct thread *thread) 193 { 194 u64 db_id; 195 196 db_id = ++dbe->comm_thread_last_db_id; 197 198 if (dbe->export_comm_thread) 199 return dbe->export_comm_thread(dbe, db_id, comm, thread); 200 201 return 0; 202 } 203 204 int db_export__dso(struct db_export *dbe, struct dso *dso, 205 struct machine *machine) 206 { 207 if (dso->db_id) 208 return 0; 209 210 dso->db_id = ++dbe->dso_last_db_id; 211 212 if (dbe->export_dso) 213 return dbe->export_dso(dbe, dso, machine); 214 215 return 0; 216 } 217 218 int db_export__symbol(struct db_export *dbe, struct symbol *sym, 219 struct dso *dso) 220 { 221 u64 *sym_db_id = symbol__priv(sym); 222 223 if (*sym_db_id) 224 return 0; 225 226 *sym_db_id = ++dbe->symbol_last_db_id; 227 228 if (dbe->export_symbol) 229 return dbe->export_symbol(dbe, sym, dso); 230 231 return 0; 232 } 233 234 static struct thread *get_main_thread(struct machine *machine, struct thread *thread) 235 { 236 if (thread->pid_ == thread->tid) 237 return thread; 238 239 if (thread->pid_ == -1) 240 return NULL; 241 242 return machine__find_thread(machine, thread->pid_, thread->pid_); 243 } 244 245 static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, 246 u64 *dso_db_id, u64 *sym_db_id, u64 *offset) 247 { 248 int err; 249 250 if (al->map) { 251 struct dso *dso = al->map->dso; 252 253 err = db_export__dso(dbe, dso, al->machine); 254 if (err) 255 return err; 256 *dso_db_id = dso->db_id; 257 258 if (!al->sym) { 259 al->sym = symbol__new(al->addr, 0, 0, "unknown"); 260 if (al->sym) 261 symbols__insert(&dso->symbols[al->map->type], 262 al->sym); 263 } 264 265 if (al->sym) { 266 u64 *db_id = symbol__priv(al->sym); 267 268 err = db_export__symbol(dbe, al->sym, dso); 269 if (err) 270 return err; 271 *sym_db_id = *db_id; 272 *offset = al->addr - al->sym->start; 273 } 274 } 275 276 return 0; 277 } 278 279 int db_export__branch_type(struct db_export *dbe, u32 branch_type, 280 const char *name) 281 { 282 if (dbe->export_branch_type) 283 return dbe->export_branch_type(dbe, branch_type, name); 284 285 return 0; 286 } 287 288 int db_export__sample(struct db_export *dbe, union perf_event *event, 289 struct perf_sample *sample, struct perf_evsel *evsel, 290 struct addr_location *al) 291 { 292 struct thread* thread = al->thread; 293 struct export_sample es = { 294 .event = event, 295 .sample = sample, 296 .evsel = evsel, 297 .al = al, 298 }; 299 struct thread *main_thread; 300 struct comm *comm = NULL; 301 int err; 302 303 err = db_export__evsel(dbe, evsel); 304 if (err) 305 return err; 306 307 err = db_export__machine(dbe, al->machine); 308 if (err) 309 return err; 310 311 /* FIXME: check refcounting for get_main_thread, that calls machine__find_thread... */ 312 main_thread = get_main_thread(al->machine, thread); 313 if (main_thread) 314 comm = machine__thread_exec_comm(al->machine, main_thread); 315 316 err = db_export__thread(dbe, thread, al->machine, comm); 317 if (err) 318 return err; 319 320 if (comm) { 321 err = db_export__comm(dbe, comm, main_thread); 322 if (err) 323 return err; 324 es.comm_db_id = comm->db_id; 325 } 326 327 es.db_id = ++dbe->sample_last_db_id; 328 329 err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset); 330 if (err) 331 return err; 332 333 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 334 sample_addr_correlates_sym(&evsel->attr)) { 335 struct addr_location addr_al; 336 337 perf_event__preprocess_sample_addr(event, sample, thread, &addr_al); 338 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id, 339 &es.addr_sym_db_id, &es.addr_offset); 340 if (err) 341 return err; 342 if (dbe->crp) { 343 err = thread_stack__process(thread, comm, sample, al, 344 &addr_al, es.db_id, 345 dbe->crp); 346 if (err) 347 return err; 348 } 349 } 350 351 if (dbe->export_sample) 352 return dbe->export_sample(dbe, &es); 353 354 return 0; 355 } 356 357 static struct { 358 u32 branch_type; 359 const char *name; 360 } branch_types[] = { 361 {0, "no branch"}, 362 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, 363 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, 364 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"}, 365 {PERF_IP_FLAG_BRANCH, "unconditional jump"}, 366 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, 367 "software interrupt"}, 368 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, 369 "return from interrupt"}, 370 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, 371 "system call"}, 372 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, 373 "return from system call"}, 374 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"}, 375 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | 376 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"}, 377 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"}, 378 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"}, 379 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"}, 380 {0, NULL} 381 }; 382 383 int db_export__branch_types(struct db_export *dbe) 384 { 385 int i, err = 0; 386 387 for (i = 0; branch_types[i].name ; i++) { 388 err = db_export__branch_type(dbe, branch_types[i].branch_type, 389 branch_types[i].name); 390 if (err) 391 break; 392 } 393 return err; 394 } 395 396 int db_export__call_path(struct db_export *dbe, struct call_path *cp) 397 { 398 int err; 399 400 if (cp->db_id) 401 return 0; 402 403 if (cp->parent) { 404 err = db_export__call_path(dbe, cp->parent); 405 if (err) 406 return err; 407 } 408 409 cp->db_id = ++dbe->call_path_last_db_id; 410 411 if (dbe->export_call_path) 412 return dbe->export_call_path(dbe, cp); 413 414 return 0; 415 } 416 417 int db_export__call_return(struct db_export *dbe, struct call_return *cr) 418 { 419 int err; 420 421 if (cr->db_id) 422 return 0; 423 424 err = db_export__call_path(dbe, cr->cp); 425 if (err) 426 return err; 427 428 cr->db_id = ++dbe->call_return_last_db_id; 429 430 if (dbe->export_call_return) 431 return dbe->export_call_return(dbe, cr); 432 433 return 0; 434 } 435