/* Kretprobe handler */ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri, struct pt_regs *regs) { struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); struct kretprobe_trace_entry *entry; struct ring_buffer_event *event; struct ring_buffer *buffer; int size, i, pc; unsigned long irq_flags; struct ftrace_event_call *call = &tp->call; local_save_flags(irq_flags); pc = preempt_count(); size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); event = trace_current_buffer_lock_reserve(&buffer, call->id, size, irq_flags, pc); if (!event) return; entry = ring_buffer_event_data(event); entry->nargs = tp->nr_args; entry->func = (unsigned long)tp->rp.kp.addr; entry->ret_ip = (unsigned long)ri->ret_addr; for (i = 0; i < tp->nr_args; i++) entry->args[i] = call_fetch(&tp->args[i].fetch, regs); if (!filter_current_check_discard(buffer, call, entry, event)) trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); }
/* Kretprobe profile handler */ static __kprobes void kretprobe_profile_func(struct kretprobe_instance *ri, struct pt_regs *regs) { struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp); struct ftrace_event_call *call = &tp->call; struct kretprobe_trace_entry *entry; int size, __size, i; unsigned long irq_flags; int rctx; __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args); size = ALIGN(__size + sizeof(u32), sizeof(u64)); size -= sizeof(u32); if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE, "profile buffer not large enough")) return; entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags); if (!entry) return; entry->nargs = tp->nr_args; entry->func = (unsigned long)tp->rp.kp.addr; entry->ret_ip = (unsigned long)ri->ret_addr; for (i = 0; i < tp->nr_args; i++) entry->args[i] = call_fetch(&tp->args[i].fetch, regs); ftrace_perf_buf_submit(entry, size, rctx, entry->ret_ip, 1, irq_flags); }
static __kprobes unsigned long fetch_indirect(struct pt_regs *regs, void *data) { struct indirect_fetch_data *ind = data; unsigned long addr; addr = call_fetch(&ind->orig, regs); if (addr) { addr += ind->offset; return fetch_memory(regs, (void *)addr); } else return 0; }
void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, void *data, void *dest) { struct deref_fetch_param *dprm = data; unsigned long addr; call_fetch(&dprm->orig, regs, &addr); if (addr && dprm->fetch_size) { addr += dprm->offset; dprm->fetch_size(regs, (void *)addr, dest); } else *(string_size *)dest = 0; }