197d5a220SFrederic Weisbecker /* 297d5a220SFrederic Weisbecker * trace event based perf event profiling/tracing 397d5a220SFrederic Weisbecker * 490eec103SPeter Zijlstra * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra 597d5a220SFrederic Weisbecker * Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com> 697d5a220SFrederic Weisbecker */ 797d5a220SFrederic Weisbecker 897d5a220SFrederic Weisbecker #include <linux/module.h> 997d5a220SFrederic Weisbecker #include <linux/kprobes.h> 1097d5a220SFrederic Weisbecker #include "trace.h" 11e12f03d7SSong Liu #include "trace_probe.h" 1297d5a220SFrederic Weisbecker 136016ee13SNamhyung Kim static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS]; 1497d5a220SFrederic Weisbecker 15eb1e7961SFrederic Weisbecker /* 16eb1e7961SFrederic Weisbecker * Force it to be aligned to unsigned long to avoid misaligned accesses 17eb1e7961SFrederic Weisbecker * suprises 18eb1e7961SFrederic Weisbecker */ 19eb1e7961SFrederic Weisbecker typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) 20eb1e7961SFrederic Weisbecker perf_trace_t; 2197d5a220SFrederic Weisbecker 2297d5a220SFrederic Weisbecker /* Count the events in use (per event id, not per instance) */ 2397d5a220SFrederic Weisbecker static int total_ref_count; 2497d5a220SFrederic Weisbecker 252425bcb9SSteven Rostedt (Red Hat) static int perf_trace_event_perm(struct trace_event_call *tp_event, 2661c32659SFrederic Weisbecker struct perf_event *p_event) 2761c32659SFrederic Weisbecker { 28d5b5f391SPeter Zijlstra if (tp_event->perf_perm) { 29d5b5f391SPeter Zijlstra int ret = tp_event->perf_perm(tp_event, p_event); 30d5b5f391SPeter Zijlstra if (ret) 31d5b5f391SPeter Zijlstra return ret; 32d5b5f391SPeter Zijlstra } 33d5b5f391SPeter Zijlstra 34f4be073dSJiri Olsa /* 35f4be073dSJiri Olsa * We checked and allowed to create parent, 36f4be073dSJiri Olsa * allow children without checking. 37f4be073dSJiri Olsa */ 38f4be073dSJiri Olsa if (p_event->parent) 39f4be073dSJiri Olsa return 0; 40f4be073dSJiri Olsa 41f4be073dSJiri Olsa /* 42f4be073dSJiri Olsa * It's ok to check current process (owner) permissions in here, 43f4be073dSJiri Olsa * because code below is called only via perf_event_open syscall. 44f4be073dSJiri Olsa */ 45f4be073dSJiri Olsa 46ced39002SJiri Olsa /* The ftrace function trace is allowed only for root. */ 47cfa77bc4SJiri Olsa if (ftrace_event_is_function(tp_event)) { 48cfa77bc4SJiri Olsa if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) 49ced39002SJiri Olsa return -EPERM; 50ced39002SJiri Olsa 510a74c5b3SJiri Olsa if (!is_sampling_event(p_event)) 520a74c5b3SJiri Olsa return 0; 530a74c5b3SJiri Olsa 54cfa77bc4SJiri Olsa /* 55cfa77bc4SJiri Olsa * We don't allow user space callchains for function trace 56cfa77bc4SJiri Olsa * event, due to issues with page faults while tracing page 57cfa77bc4SJiri Olsa * fault handler and its overall trickiness nature. 58cfa77bc4SJiri Olsa */ 59cfa77bc4SJiri Olsa if (!p_event->attr.exclude_callchain_user) 60cfa77bc4SJiri Olsa return -EINVAL; 6163c45f4bSJiri Olsa 6263c45f4bSJiri Olsa /* 6363c45f4bSJiri Olsa * Same reason to disable user stack dump as for user space 6463c45f4bSJiri Olsa * callchains above. 6563c45f4bSJiri Olsa */ 6663c45f4bSJiri Olsa if (p_event->attr.sample_type & PERF_SAMPLE_STACK_USER) 6763c45f4bSJiri Olsa return -EINVAL; 68cfa77bc4SJiri Olsa } 69cfa77bc4SJiri Olsa 7061c32659SFrederic Weisbecker /* No tracing, just counting, so no obvious leak */ 7161c32659SFrederic Weisbecker if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) 7261c32659SFrederic Weisbecker return 0; 7361c32659SFrederic Weisbecker 7461c32659SFrederic Weisbecker /* Some events are ok to be traced by non-root users... */ 7561c32659SFrederic Weisbecker if (p_event->attach_state == PERF_ATTACH_TASK) { 7661c32659SFrederic Weisbecker if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY) 7761c32659SFrederic Weisbecker return 0; 7861c32659SFrederic Weisbecker } 7961c32659SFrederic Weisbecker 8061c32659SFrederic Weisbecker /* 8161c32659SFrederic Weisbecker * ...otherwise raw tracepoint data can be a severe data leak, 8261c32659SFrederic Weisbecker * only allow root to have these. 8361c32659SFrederic Weisbecker */ 8461c32659SFrederic Weisbecker if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) 8561c32659SFrederic Weisbecker return -EPERM; 8661c32659SFrederic Weisbecker 8761c32659SFrederic Weisbecker return 0; 8861c32659SFrederic Weisbecker } 8961c32659SFrederic Weisbecker 902425bcb9SSteven Rostedt (Red Hat) static int perf_trace_event_reg(struct trace_event_call *tp_event, 911c024ecaSPeter Zijlstra struct perf_event *p_event) 9297d5a220SFrederic Weisbecker { 936016ee13SNamhyung Kim struct hlist_head __percpu *list; 94ceec0b6fSJiri Olsa int ret = -ENOMEM; 951c024ecaSPeter Zijlstra int cpu; 9697d5a220SFrederic Weisbecker 971c024ecaSPeter Zijlstra p_event->tp_event = tp_event; 981c024ecaSPeter Zijlstra if (tp_event->perf_refcount++ > 0) 9997d5a220SFrederic Weisbecker return 0; 10097d5a220SFrederic Weisbecker 1011c024ecaSPeter Zijlstra list = alloc_percpu(struct hlist_head); 1021c024ecaSPeter Zijlstra if (!list) 1031c024ecaSPeter Zijlstra goto fail; 1041c024ecaSPeter Zijlstra 1051c024ecaSPeter Zijlstra for_each_possible_cpu(cpu) 1061c024ecaSPeter Zijlstra INIT_HLIST_HEAD(per_cpu_ptr(list, cpu)); 1071c024ecaSPeter Zijlstra 1081c024ecaSPeter Zijlstra tp_event->perf_events = list; 10997d5a220SFrederic Weisbecker 11097d5a220SFrederic Weisbecker if (!total_ref_count) { 1116016ee13SNamhyung Kim char __percpu *buf; 112b7e2ecefSPeter Zijlstra int i; 113b7e2ecefSPeter Zijlstra 1147ae07ea3SFrederic Weisbecker for (i = 0; i < PERF_NR_CONTEXTS; i++) { 1156016ee13SNamhyung Kim buf = (char __percpu *)alloc_percpu(perf_trace_t); 11697d5a220SFrederic Weisbecker if (!buf) 1171c024ecaSPeter Zijlstra goto fail; 11897d5a220SFrederic Weisbecker 1191c024ecaSPeter Zijlstra perf_trace_buf[i] = buf; 120b7e2ecefSPeter Zijlstra } 12197d5a220SFrederic Weisbecker } 12297d5a220SFrederic Weisbecker 123ceec0b6fSJiri Olsa ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER, NULL); 1241c024ecaSPeter Zijlstra if (ret) 1251c024ecaSPeter Zijlstra goto fail; 1261c024ecaSPeter Zijlstra 12797d5a220SFrederic Weisbecker total_ref_count++; 12897d5a220SFrederic Weisbecker return 0; 12997d5a220SFrederic Weisbecker 1301c024ecaSPeter Zijlstra fail: 131b7e2ecefSPeter Zijlstra if (!total_ref_count) { 132b7e2ecefSPeter Zijlstra int i; 133b7e2ecefSPeter Zijlstra 1347ae07ea3SFrederic Weisbecker for (i = 0; i < PERF_NR_CONTEXTS; i++) { 135b7e2ecefSPeter Zijlstra free_percpu(perf_trace_buf[i]); 136b7e2ecefSPeter Zijlstra perf_trace_buf[i] = NULL; 137b7e2ecefSPeter Zijlstra } 13897d5a220SFrederic Weisbecker } 13997d5a220SFrederic Weisbecker 1401c024ecaSPeter Zijlstra if (!--tp_event->perf_refcount) { 1411c024ecaSPeter Zijlstra free_percpu(tp_event->perf_events); 1421c024ecaSPeter Zijlstra tp_event->perf_events = NULL; 14397d5a220SFrederic Weisbecker } 14497d5a220SFrederic Weisbecker 14597d5a220SFrederic Weisbecker return ret; 14697d5a220SFrederic Weisbecker } 14797d5a220SFrederic Weisbecker 148ceec0b6fSJiri Olsa static void perf_trace_event_unreg(struct perf_event *p_event) 149ceec0b6fSJiri Olsa { 1502425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *tp_event = p_event->tp_event; 151ceec0b6fSJiri Olsa int i; 152ceec0b6fSJiri Olsa 153ceec0b6fSJiri Olsa if (--tp_event->perf_refcount > 0) 154ceec0b6fSJiri Olsa goto out; 155ceec0b6fSJiri Olsa 156ceec0b6fSJiri Olsa tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL); 157ceec0b6fSJiri Olsa 158ceec0b6fSJiri Olsa /* 159ceec0b6fSJiri Olsa * Ensure our callback won't be called anymore. The buffers 160ceec0b6fSJiri Olsa * will be freed after that. 161ceec0b6fSJiri Olsa */ 162ceec0b6fSJiri Olsa tracepoint_synchronize_unregister(); 163ceec0b6fSJiri Olsa 164ceec0b6fSJiri Olsa free_percpu(tp_event->perf_events); 165ceec0b6fSJiri Olsa tp_event->perf_events = NULL; 166ceec0b6fSJiri Olsa 167ceec0b6fSJiri Olsa if (!--total_ref_count) { 168ceec0b6fSJiri Olsa for (i = 0; i < PERF_NR_CONTEXTS; i++) { 169ceec0b6fSJiri Olsa free_percpu(perf_trace_buf[i]); 170ceec0b6fSJiri Olsa perf_trace_buf[i] = NULL; 171ceec0b6fSJiri Olsa } 172ceec0b6fSJiri Olsa } 173ceec0b6fSJiri Olsa out: 174ceec0b6fSJiri Olsa module_put(tp_event->mod); 175ceec0b6fSJiri Olsa } 176ceec0b6fSJiri Olsa 177ceec0b6fSJiri Olsa static int perf_trace_event_open(struct perf_event *p_event) 178ceec0b6fSJiri Olsa { 1792425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *tp_event = p_event->tp_event; 180ceec0b6fSJiri Olsa return tp_event->class->reg(tp_event, TRACE_REG_PERF_OPEN, p_event); 181ceec0b6fSJiri Olsa } 182ceec0b6fSJiri Olsa 183ceec0b6fSJiri Olsa static void perf_trace_event_close(struct perf_event *p_event) 184ceec0b6fSJiri Olsa { 1852425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *tp_event = p_event->tp_event; 186ceec0b6fSJiri Olsa tp_event->class->reg(tp_event, TRACE_REG_PERF_CLOSE, p_event); 187ceec0b6fSJiri Olsa } 188ceec0b6fSJiri Olsa 1892425bcb9SSteven Rostedt (Red Hat) static int perf_trace_event_init(struct trace_event_call *tp_event, 190ceec0b6fSJiri Olsa struct perf_event *p_event) 191ceec0b6fSJiri Olsa { 192ceec0b6fSJiri Olsa int ret; 193ceec0b6fSJiri Olsa 194ceec0b6fSJiri Olsa ret = perf_trace_event_perm(tp_event, p_event); 195ceec0b6fSJiri Olsa if (ret) 196ceec0b6fSJiri Olsa return ret; 197ceec0b6fSJiri Olsa 198ceec0b6fSJiri Olsa ret = perf_trace_event_reg(tp_event, p_event); 199ceec0b6fSJiri Olsa if (ret) 200ceec0b6fSJiri Olsa return ret; 201ceec0b6fSJiri Olsa 202ceec0b6fSJiri Olsa ret = perf_trace_event_open(p_event); 203ceec0b6fSJiri Olsa if (ret) { 204ceec0b6fSJiri Olsa perf_trace_event_unreg(p_event); 205ceec0b6fSJiri Olsa return ret; 206ceec0b6fSJiri Olsa } 207ceec0b6fSJiri Olsa 208ceec0b6fSJiri Olsa return 0; 209ceec0b6fSJiri Olsa } 210ceec0b6fSJiri Olsa 2111c024ecaSPeter Zijlstra int perf_trace_init(struct perf_event *p_event) 21297d5a220SFrederic Weisbecker { 2132425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *tp_event; 2140022ceddSVince Weaver u64 event_id = p_event->attr.config; 21597d5a220SFrederic Weisbecker int ret = -EINVAL; 21697d5a220SFrederic Weisbecker 21797d5a220SFrederic Weisbecker mutex_lock(&event_mutex); 2181c024ecaSPeter Zijlstra list_for_each_entry(tp_event, &ftrace_events, list) { 219ff5f149bSSteven Rostedt if (tp_event->event.type == event_id && 220a1d0ce82SSteven Rostedt tp_event->class && tp_event->class->reg && 2211c024ecaSPeter Zijlstra try_module_get(tp_event->mod)) { 2221c024ecaSPeter Zijlstra ret = perf_trace_event_init(tp_event, p_event); 2239cb627d5SLi Zefan if (ret) 2249cb627d5SLi Zefan module_put(tp_event->mod); 22597d5a220SFrederic Weisbecker break; 22697d5a220SFrederic Weisbecker } 22797d5a220SFrederic Weisbecker } 22897d5a220SFrederic Weisbecker mutex_unlock(&event_mutex); 22997d5a220SFrederic Weisbecker 23097d5a220SFrederic Weisbecker return ret; 23197d5a220SFrederic Weisbecker } 23297d5a220SFrederic Weisbecker 233ceec0b6fSJiri Olsa void perf_trace_destroy(struct perf_event *p_event) 234ceec0b6fSJiri Olsa { 235ceec0b6fSJiri Olsa mutex_lock(&event_mutex); 236ceec0b6fSJiri Olsa perf_trace_event_close(p_event); 237ceec0b6fSJiri Olsa perf_trace_event_unreg(p_event); 238ceec0b6fSJiri Olsa mutex_unlock(&event_mutex); 239ceec0b6fSJiri Olsa } 240ceec0b6fSJiri Olsa 241e12f03d7SSong Liu #ifdef CONFIG_KPROBE_EVENTS 242e12f03d7SSong Liu int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe) 243e12f03d7SSong Liu { 244e12f03d7SSong Liu int ret; 245e12f03d7SSong Liu char *func = NULL; 246e12f03d7SSong Liu struct trace_event_call *tp_event; 247e12f03d7SSong Liu 248e12f03d7SSong Liu if (p_event->attr.kprobe_func) { 249e12f03d7SSong Liu func = kzalloc(KSYM_NAME_LEN, GFP_KERNEL); 250e12f03d7SSong Liu if (!func) 251e12f03d7SSong Liu return -ENOMEM; 252e12f03d7SSong Liu ret = strncpy_from_user( 253e12f03d7SSong Liu func, u64_to_user_ptr(p_event->attr.kprobe_func), 254e12f03d7SSong Liu KSYM_NAME_LEN); 2555da13ab8SMasami Hiramatsu if (ret == KSYM_NAME_LEN) 2565da13ab8SMasami Hiramatsu ret = -E2BIG; 257e12f03d7SSong Liu if (ret < 0) 258e12f03d7SSong Liu goto out; 259e12f03d7SSong Liu 260e12f03d7SSong Liu if (func[0] == '\0') { 261e12f03d7SSong Liu kfree(func); 262e12f03d7SSong Liu func = NULL; 263e12f03d7SSong Liu } 264e12f03d7SSong Liu } 265e12f03d7SSong Liu 266e12f03d7SSong Liu tp_event = create_local_trace_kprobe( 267e12f03d7SSong Liu func, (void *)(unsigned long)(p_event->attr.kprobe_addr), 268e12f03d7SSong Liu p_event->attr.probe_offset, is_retprobe); 269e12f03d7SSong Liu if (IS_ERR(tp_event)) { 270e12f03d7SSong Liu ret = PTR_ERR(tp_event); 271e12f03d7SSong Liu goto out; 272e12f03d7SSong Liu } 273e12f03d7SSong Liu 274e12f03d7SSong Liu ret = perf_trace_event_init(tp_event, p_event); 275e12f03d7SSong Liu if (ret) 276e12f03d7SSong Liu destroy_local_trace_kprobe(tp_event); 277e12f03d7SSong Liu out: 278e12f03d7SSong Liu kfree(func); 279e12f03d7SSong Liu return ret; 280e12f03d7SSong Liu } 281e12f03d7SSong Liu 282e12f03d7SSong Liu void perf_kprobe_destroy(struct perf_event *p_event) 283e12f03d7SSong Liu { 284e12f03d7SSong Liu perf_trace_event_close(p_event); 285e12f03d7SSong Liu perf_trace_event_unreg(p_event); 286e12f03d7SSong Liu 287e12f03d7SSong Liu destroy_local_trace_kprobe(p_event->tp_event); 288e12f03d7SSong Liu } 289e12f03d7SSong Liu #endif /* CONFIG_KPROBE_EVENTS */ 290e12f03d7SSong Liu 29133ea4b24SSong Liu #ifdef CONFIG_UPROBE_EVENTS 29233ea4b24SSong Liu int perf_uprobe_init(struct perf_event *p_event, bool is_retprobe) 29333ea4b24SSong Liu { 29433ea4b24SSong Liu int ret; 29533ea4b24SSong Liu char *path = NULL; 29633ea4b24SSong Liu struct trace_event_call *tp_event; 29733ea4b24SSong Liu 29833ea4b24SSong Liu if (!p_event->attr.uprobe_path) 29933ea4b24SSong Liu return -EINVAL; 30033ea4b24SSong Liu path = kzalloc(PATH_MAX, GFP_KERNEL); 30133ea4b24SSong Liu if (!path) 30233ea4b24SSong Liu return -ENOMEM; 30333ea4b24SSong Liu ret = strncpy_from_user( 30433ea4b24SSong Liu path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX); 305*0eadcc7aSSong Liu if (ret == PATH_MAX) 306*0eadcc7aSSong Liu return -E2BIG; 30733ea4b24SSong Liu if (ret < 0) 30833ea4b24SSong Liu goto out; 30933ea4b24SSong Liu if (path[0] == '\0') { 31033ea4b24SSong Liu ret = -EINVAL; 31133ea4b24SSong Liu goto out; 31233ea4b24SSong Liu } 31333ea4b24SSong Liu 31433ea4b24SSong Liu tp_event = create_local_trace_uprobe( 31533ea4b24SSong Liu path, p_event->attr.probe_offset, is_retprobe); 31633ea4b24SSong Liu if (IS_ERR(tp_event)) { 31733ea4b24SSong Liu ret = PTR_ERR(tp_event); 31833ea4b24SSong Liu goto out; 31933ea4b24SSong Liu } 32033ea4b24SSong Liu 32133ea4b24SSong Liu /* 32233ea4b24SSong Liu * local trace_uprobe need to hold event_mutex to call 32333ea4b24SSong Liu * uprobe_buffer_enable() and uprobe_buffer_disable(). 32433ea4b24SSong Liu * event_mutex is not required for local trace_kprobes. 32533ea4b24SSong Liu */ 32633ea4b24SSong Liu mutex_lock(&event_mutex); 32733ea4b24SSong Liu ret = perf_trace_event_init(tp_event, p_event); 32833ea4b24SSong Liu if (ret) 32933ea4b24SSong Liu destroy_local_trace_uprobe(tp_event); 33033ea4b24SSong Liu mutex_unlock(&event_mutex); 33133ea4b24SSong Liu out: 33233ea4b24SSong Liu kfree(path); 33333ea4b24SSong Liu return ret; 33433ea4b24SSong Liu } 33533ea4b24SSong Liu 33633ea4b24SSong Liu void perf_uprobe_destroy(struct perf_event *p_event) 33733ea4b24SSong Liu { 33833ea4b24SSong Liu mutex_lock(&event_mutex); 33933ea4b24SSong Liu perf_trace_event_close(p_event); 34033ea4b24SSong Liu perf_trace_event_unreg(p_event); 34133ea4b24SSong Liu mutex_unlock(&event_mutex); 34233ea4b24SSong Liu destroy_local_trace_uprobe(p_event->tp_event); 34333ea4b24SSong Liu } 34433ea4b24SSong Liu #endif /* CONFIG_UPROBE_EVENTS */ 34533ea4b24SSong Liu 346a4eaf7f1SPeter Zijlstra int perf_trace_add(struct perf_event *p_event, int flags) 34797d5a220SFrederic Weisbecker { 3482425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *tp_event = p_event->tp_event; 349466c81c4SPeter Zijlstra 350466c81c4SPeter Zijlstra if (!(flags & PERF_EF_START)) 351466c81c4SPeter Zijlstra p_event->hw.state = PERF_HES_STOPPED; 352466c81c4SPeter Zijlstra 353466c81c4SPeter Zijlstra /* 354466c81c4SPeter Zijlstra * If TRACE_REG_PERF_ADD returns false; no custom action was performed 355466c81c4SPeter Zijlstra * and we need to take the default action of enqueueing our event on 356466c81c4SPeter Zijlstra * the right per-cpu hlist. 357466c81c4SPeter Zijlstra */ 358466c81c4SPeter Zijlstra if (!tp_event->class->reg(tp_event, TRACE_REG_PERF_ADD, p_event)) { 3596016ee13SNamhyung Kim struct hlist_head __percpu *pcpu_list; 3601c024ecaSPeter Zijlstra struct hlist_head *list; 36197d5a220SFrederic Weisbecker 3626016ee13SNamhyung Kim pcpu_list = tp_event->perf_events; 3636016ee13SNamhyung Kim if (WARN_ON_ONCE(!pcpu_list)) 3641c024ecaSPeter Zijlstra return -EINVAL; 36597d5a220SFrederic Weisbecker 3666016ee13SNamhyung Kim list = this_cpu_ptr(pcpu_list); 3671c024ecaSPeter Zijlstra hlist_add_head_rcu(&p_event->hlist_entry, list); 368466c81c4SPeter Zijlstra } 3691c024ecaSPeter Zijlstra 370466c81c4SPeter Zijlstra return 0; 3711c024ecaSPeter Zijlstra } 3721c024ecaSPeter Zijlstra 373a4eaf7f1SPeter Zijlstra void perf_trace_del(struct perf_event *p_event, int flags) 3741c024ecaSPeter Zijlstra { 3752425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *tp_event = p_event->tp_event; 376466c81c4SPeter Zijlstra 377466c81c4SPeter Zijlstra /* 378466c81c4SPeter Zijlstra * If TRACE_REG_PERF_DEL returns false; no custom action was performed 379466c81c4SPeter Zijlstra * and we need to take the default action of dequeueing our event from 380466c81c4SPeter Zijlstra * the right per-cpu hlist. 381466c81c4SPeter Zijlstra */ 382466c81c4SPeter Zijlstra if (!tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event)) 3831c024ecaSPeter Zijlstra hlist_del_rcu(&p_event->hlist_entry); 3841c024ecaSPeter Zijlstra } 3851c024ecaSPeter Zijlstra 3861e1dcd93SAlexei Starovoitov void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp) 38797d5a220SFrederic Weisbecker { 3881c024ecaSPeter Zijlstra char *raw_data; 3891e1dcd93SAlexei Starovoitov int rctx; 39097d5a220SFrederic Weisbecker 391eb1e7961SFrederic Weisbecker BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long)); 392eb1e7961SFrederic Weisbecker 393cd92bf61SOleg Nesterov if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, 394cd92bf61SOleg Nesterov "perf buffer not large enough")) 395cd92bf61SOleg Nesterov return NULL; 396cd92bf61SOleg Nesterov 3971e1dcd93SAlexei Starovoitov *rctxp = rctx = perf_swevent_get_recursion_context(); 3981e1dcd93SAlexei Starovoitov if (rctx < 0) 3991c024ecaSPeter Zijlstra return NULL; 40097d5a220SFrederic Weisbecker 40186038c5eSPeter Zijlstra (Intel) if (regs) 4021e1dcd93SAlexei Starovoitov *regs = this_cpu_ptr(&__perf_regs[rctx]); 4031e1dcd93SAlexei Starovoitov raw_data = this_cpu_ptr(perf_trace_buf[rctx]); 40497d5a220SFrederic Weisbecker 40597d5a220SFrederic Weisbecker /* zero the dead bytes from align to not leak stack to user */ 406eb1e7961SFrederic Weisbecker memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64)); 4071e1dcd93SAlexei Starovoitov return raw_data; 4081e1dcd93SAlexei Starovoitov } 4091e1dcd93SAlexei Starovoitov EXPORT_SYMBOL_GPL(perf_trace_buf_alloc); 4101e1dcd93SAlexei Starovoitov NOKPROBE_SYMBOL(perf_trace_buf_alloc); 41197d5a220SFrederic Weisbecker 4121e1dcd93SAlexei Starovoitov void perf_trace_buf_update(void *record, u16 type) 4131e1dcd93SAlexei Starovoitov { 4141e1dcd93SAlexei Starovoitov struct trace_entry *entry = record; 4151e1dcd93SAlexei Starovoitov int pc = preempt_count(); 4161e1dcd93SAlexei Starovoitov unsigned long flags; 4171e1dcd93SAlexei Starovoitov 41887f44bbcSPeter Zijlstra local_save_flags(flags); 41987f44bbcSPeter Zijlstra tracing_generic_entry_update(entry, flags, pc); 42097d5a220SFrederic Weisbecker entry->type = type; 42197d5a220SFrederic Weisbecker } 4221e1dcd93SAlexei Starovoitov NOKPROBE_SYMBOL(perf_trace_buf_update); 423ced39002SJiri Olsa 424ced39002SJiri Olsa #ifdef CONFIG_FUNCTION_TRACER 425ced39002SJiri Olsa static void 4262f5f6ad9SSteven Rostedt perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip, 427a1e2e31dSSteven Rostedt struct ftrace_ops *ops, struct pt_regs *pt_regs) 428ced39002SJiri Olsa { 429ced39002SJiri Olsa struct ftrace_entry *entry; 430466c81c4SPeter Zijlstra struct perf_event *event; 431466c81c4SPeter Zijlstra struct hlist_head head; 432ced39002SJiri Olsa struct pt_regs regs; 433ced39002SJiri Olsa int rctx; 434ced39002SJiri Olsa 435466c81c4SPeter Zijlstra if ((unsigned long)ops->private != smp_processor_id()) 436b8ebfd3fSOleg Nesterov return; 437b8ebfd3fSOleg Nesterov 438466c81c4SPeter Zijlstra event = container_of(ops, struct perf_event, ftrace_ops); 439466c81c4SPeter Zijlstra 440466c81c4SPeter Zijlstra /* 441466c81c4SPeter Zijlstra * @event->hlist entry is NULL (per INIT_HLIST_NODE), and all 442466c81c4SPeter Zijlstra * the perf code does is hlist_for_each_entry_rcu(), so we can 443466c81c4SPeter Zijlstra * get away with simply setting the @head.first pointer in order 444466c81c4SPeter Zijlstra * to create a singular list. 445466c81c4SPeter Zijlstra */ 446466c81c4SPeter Zijlstra head.first = &event->hlist_entry; 447466c81c4SPeter Zijlstra 448ced39002SJiri Olsa #define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \ 449ced39002SJiri Olsa sizeof(u64)) - sizeof(u32)) 450ced39002SJiri Olsa 451ced39002SJiri Olsa BUILD_BUG_ON(ENTRY_SIZE > PERF_MAX_TRACE_SIZE); 452ced39002SJiri Olsa 453ec5e099dSAlexei Starovoitov memset(®s, 0, sizeof(regs)); 454ced39002SJiri Olsa perf_fetch_caller_regs(®s); 455ced39002SJiri Olsa 4561e1dcd93SAlexei Starovoitov entry = perf_trace_buf_alloc(ENTRY_SIZE, NULL, &rctx); 457ced39002SJiri Olsa if (!entry) 458ced39002SJiri Olsa return; 459ced39002SJiri Olsa 460ced39002SJiri Olsa entry->ip = ip; 461ced39002SJiri Olsa entry->parent_ip = parent_ip; 4621e1dcd93SAlexei Starovoitov perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, TRACE_FN, 463466c81c4SPeter Zijlstra 1, ®s, &head, NULL); 464ced39002SJiri Olsa 465ced39002SJiri Olsa #undef ENTRY_SIZE 466ced39002SJiri Olsa } 467ced39002SJiri Olsa 468ced39002SJiri Olsa static int perf_ftrace_function_register(struct perf_event *event) 469ced39002SJiri Olsa { 470ced39002SJiri Olsa struct ftrace_ops *ops = &event->ftrace_ops; 471ced39002SJiri Olsa 4721dd311e6SPeter Zijlstra ops->flags = FTRACE_OPS_FL_RCU; 473ced39002SJiri Olsa ops->func = perf_ftrace_function_call; 474466c81c4SPeter Zijlstra ops->private = (void *)(unsigned long)nr_cpu_ids; 475466c81c4SPeter Zijlstra 476ced39002SJiri Olsa return register_ftrace_function(ops); 477ced39002SJiri Olsa } 478ced39002SJiri Olsa 479ced39002SJiri Olsa static int perf_ftrace_function_unregister(struct perf_event *event) 480ced39002SJiri Olsa { 481ced39002SJiri Olsa struct ftrace_ops *ops = &event->ftrace_ops; 4825500fa51SJiri Olsa int ret = unregister_ftrace_function(ops); 4835500fa51SJiri Olsa ftrace_free_filter(ops); 4845500fa51SJiri Olsa return ret; 485ced39002SJiri Olsa } 486ced39002SJiri Olsa 4872425bcb9SSteven Rostedt (Red Hat) int perf_ftrace_event_register(struct trace_event_call *call, 488ced39002SJiri Olsa enum trace_reg type, void *data) 489ced39002SJiri Olsa { 490466c81c4SPeter Zijlstra struct perf_event *event = data; 491466c81c4SPeter Zijlstra 492ced39002SJiri Olsa switch (type) { 493ced39002SJiri Olsa case TRACE_REG_REGISTER: 494ced39002SJiri Olsa case TRACE_REG_UNREGISTER: 495ced39002SJiri Olsa break; 496ced39002SJiri Olsa case TRACE_REG_PERF_REGISTER: 497ced39002SJiri Olsa case TRACE_REG_PERF_UNREGISTER: 498ced39002SJiri Olsa return 0; 499ced39002SJiri Olsa case TRACE_REG_PERF_OPEN: 500ced39002SJiri Olsa return perf_ftrace_function_register(data); 501ced39002SJiri Olsa case TRACE_REG_PERF_CLOSE: 502ced39002SJiri Olsa return perf_ftrace_function_unregister(data); 503ced39002SJiri Olsa case TRACE_REG_PERF_ADD: 504466c81c4SPeter Zijlstra event->ftrace_ops.private = (void *)(unsigned long)smp_processor_id(); 505466c81c4SPeter Zijlstra return 1; 506ced39002SJiri Olsa case TRACE_REG_PERF_DEL: 507466c81c4SPeter Zijlstra event->ftrace_ops.private = (void *)(unsigned long)nr_cpu_ids; 508466c81c4SPeter Zijlstra return 1; 509ced39002SJiri Olsa } 510ced39002SJiri Olsa 511ced39002SJiri Olsa return -EINVAL; 512ced39002SJiri Olsa } 513ced39002SJiri Olsa #endif /* CONFIG_FUNCTION_TRACER */ 514