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 28struct deferred_export { 29 struct list_head node; 30 struct comm *comm; 31}; 32 33static 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 51static 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 63static 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 77int 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 84int db_export__flush(struct db_export *dbe) 85{ 86 return db_export__deferred(dbe); 87} 88 89void 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 96int 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 109int 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 122int 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 164out_put: 165 thread__put(main_thread); 166 return err; 167} 168 169int 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 191int 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 204int 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 218int 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 234static struct thread *get_main_thread(struct machine *machine, struct thread *thread) 235{ 236 if (thread->pid_ == thread->tid) 237 return thread__get(thread); 238 239 if (thread->pid_ == -1) 240 return NULL; 241 242 return machine__find_thread(machine, thread->pid_, thread->pid_); 243} 244 245static 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 279int 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 288int 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 main_thread = get_main_thread(al->machine, thread); 312 if (main_thread) 313 comm = machine__thread_exec_comm(al->machine, main_thread); 314 315 err = db_export__thread(dbe, thread, al->machine, comm); 316 if (err) 317 goto out_put; 318 319 if (comm) { 320 err = db_export__comm(dbe, comm, main_thread); 321 if (err) 322 goto out_put; 323 es.comm_db_id = comm->db_id; 324 } 325 326 es.db_id = ++dbe->sample_last_db_id; 327 328 err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset); 329 if (err) 330 goto out_put; 331 332 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 333 sample_addr_correlates_sym(&evsel->attr)) { 334 struct addr_location addr_al; 335 336 perf_event__preprocess_sample_addr(event, sample, thread, &addr_al); 337 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id, 338 &es.addr_sym_db_id, &es.addr_offset); 339 if (err) 340 goto out_put; 341 if (dbe->crp) { 342 err = thread_stack__process(thread, comm, sample, al, 343 &addr_al, es.db_id, 344 dbe->crp); 345 if (err) 346 goto out_put; 347 } 348 } 349 350 if (dbe->export_sample) 351 err = dbe->export_sample(dbe, &es); 352 353out_put: 354 thread__put(main_thread); 355 return err; 356} 357 358static struct { 359 u32 branch_type; 360 const char *name; 361} branch_types[] = { 362 {0, "no branch"}, 363 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, 364 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, 365 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"}, 366 {PERF_IP_FLAG_BRANCH, "unconditional jump"}, 367 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, 368 "software interrupt"}, 369 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, 370 "return from interrupt"}, 371 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, 372 "system call"}, 373 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, 374 "return from system call"}, 375 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"}, 376 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | 377 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"}, 378 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"}, 379 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"}, 380 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"}, 381 {0, NULL} 382}; 383 384int db_export__branch_types(struct db_export *dbe) 385{ 386 int i, err = 0; 387 388 for (i = 0; branch_types[i].name ; i++) { 389 err = db_export__branch_type(dbe, branch_types[i].branch_type, 390 branch_types[i].name); 391 if (err) 392 break; 393 } 394 return err; 395} 396 397int db_export__call_path(struct db_export *dbe, struct call_path *cp) 398{ 399 int err; 400 401 if (cp->db_id) 402 return 0; 403 404 if (cp->parent) { 405 err = db_export__call_path(dbe, cp->parent); 406 if (err) 407 return err; 408 } 409 410 cp->db_id = ++dbe->call_path_last_db_id; 411 412 if (dbe->export_call_path) 413 return dbe->export_call_path(dbe, cp); 414 415 return 0; 416} 417 418int db_export__call_return(struct db_export *dbe, struct call_return *cr) 419{ 420 int err; 421 422 if (cr->db_id) 423 return 0; 424 425 err = db_export__call_path(dbe, cr->cp); 426 if (err) 427 return err; 428 429 cr->db_id = ++dbe->call_return_last_db_id; 430 431 if (dbe->export_call_return) 432 return dbe->export_call_return(dbe, cr); 433 434 return 0; 435} 436