linux/kernel/trace/trace_uprobe.c

// SPDX-License-Identifier: GPL-2.0
/*
 * uprobes-based tracing events
 *
 * Copyright (C) IBM Corporation, 2010-2012
 * Author:	Srikar Dronamraju <[email protected]>
 */
#define pr_fmt(fmt)

#include <linux/bpf-cgroup.h>
#include <linux/security.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/uprobes.h>
#include <linux/namei.h>
#include <linux/string.h>
#include <linux/rculist.h>
#include <linux/filter.h>

#include "trace_dynevent.h"
#include "trace_probe.h"
#include "trace_probe_tmpl.h"

#define UPROBE_EVENT_SYSTEM

struct uprobe_trace_entry_head {};

#define SIZEOF_TRACE_ENTRY(is_return)

#define DATAOF_TRACE_ENTRY(entry, is_return)

static int trace_uprobe_create(const char *raw_command);
static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev);
static int trace_uprobe_release(struct dyn_event *ev);
static bool trace_uprobe_is_busy(struct dyn_event *ev);
static bool trace_uprobe_match(const char *system, const char *event,
			int argc, const char **argv, struct dyn_event *ev);

static struct dyn_event_operations trace_uprobe_ops =;

/*
 * uprobe event core functions
 */
struct trace_uprobe {};

static bool is_trace_uprobe(struct dyn_event *ev)
{}

static struct trace_uprobe *to_trace_uprobe(struct dyn_event *ev)
{}

/**
 * for_each_trace_uprobe - iterate over the trace_uprobe list
 * @pos:	the struct trace_uprobe * for each entry
 * @dpos:	the struct dyn_event * to use as a loop cursor
 */
#define for_each_trace_uprobe(pos, dpos)

static int register_uprobe_event(struct trace_uprobe *tu);
static int unregister_uprobe_event(struct trace_uprobe *tu);

static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
static int uretprobe_dispatcher(struct uprobe_consumer *con,
				unsigned long func, struct pt_regs *regs);

#ifdef CONFIG_STACK_GROWSUP
static unsigned long adjust_stack_addr(unsigned long addr, unsigned int n)
{
	return addr - (n * sizeof(long));
}
#else
static unsigned long adjust_stack_addr(unsigned long addr, unsigned int n)
{}
#endif

static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
{}

/*
 * Uprobes-specific fetch functions
 */
static nokprobe_inline int
probe_mem_read(void *dest, void *src, size_t size)
{}

static nokprobe_inline int
probe_mem_read_user(void *dest, void *src, size_t size)
{}

/*
 * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
 * length and relative data location.
 */
static nokprobe_inline int
fetch_store_string(unsigned long addr, void *dest, void *base)
{}

static nokprobe_inline int
fetch_store_string_user(unsigned long addr, void *dest, void *base)
{}

/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
fetch_store_strlen(unsigned long addr)
{}

static nokprobe_inline int
fetch_store_strlen_user(unsigned long addr)
{}

static unsigned long translate_user_vaddr(unsigned long file_offset)
{}

/* Note that we don't verify it, since the code does not come from user space */
static int
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
		   void *dest, void *base)
{}
NOKPROBE_SYMBOL()

static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
{}

static inline bool uprobe_filter_is_empty(struct trace_uprobe_filter *filter)
{}

static inline bool is_ret_probe(struct trace_uprobe *tu)
{}

static bool trace_uprobe_is_busy(struct dyn_event *ev)
{}

static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
					    int argc, const char **argv)
{}

static bool trace_uprobe_match(const char *system, const char *event,
			int argc, const char **argv, struct dyn_event *ev)
{}

static nokprobe_inline struct trace_uprobe *
trace_uprobe_primary_from_call(struct trace_event_call *call)
{}

/*
 * Allocate new trace_uprobe and initialize it (including uprobes).
 */
static struct trace_uprobe *
alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
{}

static void free_trace_uprobe(struct trace_uprobe *tu)
{}

static struct trace_uprobe *find_probe_event(const char *event, const char *group)
{}

/* Unregister a trace_uprobe and probe_event */
static int unregister_trace_uprobe(struct trace_uprobe *tu)
{}

static bool trace_uprobe_has_same_uprobe(struct trace_uprobe *orig,
					 struct trace_uprobe *comp)
{}

static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
{}

/*
 * Uprobe with multiple reference counter is not allowed. i.e.
 * If inode and offset matches, reference counter offset *must*
 * match as well. Though, there is one exception: If user is
 * replacing old trace_uprobe with new one(same group/event),
 * then we allow same uprobe with new reference counter as far
 * as the new one does not conflict with any other existing
 * ones.
 */
static int validate_ref_ctr_offset(struct trace_uprobe *new)
{}

/* Register a trace_uprobe and probe_event */
static int register_trace_uprobe(struct trace_uprobe *tu)
{}

/*
 * Argument syntax:
 *  - Add uprobe: p|r[:[GRP/][EVENT]] PATH:OFFSET[%return][(REF)] [FETCHARGS]
 */
static int __trace_uprobe_create(int argc, const char **argv)
{}

int trace_uprobe_create(const char *raw_command)
{}

static int create_or_delete_trace_uprobe(const char *raw_command)
{}

static int trace_uprobe_release(struct dyn_event *ev)
{}

/* Probes listing interfaces */
static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
{}

static int probes_seq_show(struct seq_file *m, void *v)
{}

static const struct seq_operations probes_seq_op =;

static int probes_open(struct inode *inode, struct file *file)
{}

static ssize_t probes_write(struct file *file, const char __user *buffer,
			    size_t count, loff_t *ppos)
{}

static const struct file_operations uprobe_events_ops =;

/* Probes profiling interfaces */
static int probes_profile_seq_show(struct seq_file *m, void *v)
{}

static const struct seq_operations profile_seq_op =;

static int profile_open(struct inode *inode, struct file *file)
{}

static const struct file_operations uprobe_profile_ops =;

struct uprobe_cpu_buffer {};
static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer;
static int uprobe_buffer_refcnt;

static int uprobe_buffer_init(void)
{}

static int uprobe_buffer_enable(void)
{}

static void uprobe_buffer_disable(void)
{}

static struct uprobe_cpu_buffer *uprobe_buffer_get(void)
{}

static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb)
{}

static struct uprobe_cpu_buffer *prepare_uprobe_buffer(struct trace_uprobe *tu,
						       struct pt_regs *regs,
						       struct uprobe_cpu_buffer **ucbp)
{}

static void __uprobe_trace_func(struct trace_uprobe *tu,
				unsigned long func, struct pt_regs *regs,
				struct uprobe_cpu_buffer *ucb,
				struct trace_event_file *trace_file)
{}

/* uprobe handler */
static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
			     struct uprobe_cpu_buffer **ucbp)
{}

static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
				 struct pt_regs *regs,
				 struct uprobe_cpu_buffer **ucbp)
{}

/* Event entry printers */
static enum print_line_t
print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event)
{}

filter_func_t;

static int trace_uprobe_enable(struct trace_uprobe *tu, filter_func_t filter)
{}

static void __probe_event_disable(struct trace_probe *tp)
{}

static int probe_event_enable(struct trace_event_call *call,
			struct trace_event_file *file, filter_func_t filter)
{}

static void probe_event_disable(struct trace_event_call *call,
				struct trace_event_file *file)
{}

static int uprobe_event_define_fields(struct trace_event_call *event_call)
{}

#ifdef CONFIG_PERF_EVENTS
static bool
__uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm)
{}

static inline bool
trace_uprobe_filter_event(struct trace_uprobe_filter *filter,
			  struct perf_event *event)
{}

static bool trace_uprobe_filter_remove(struct trace_uprobe_filter *filter,
				       struct perf_event *event)
{}

/* This returns true if the filter always covers target mm */
static bool trace_uprobe_filter_add(struct trace_uprobe_filter *filter,
				    struct perf_event *event)
{}

static int uprobe_perf_close(struct trace_event_call *call,
			     struct perf_event *event)
{}

static int uprobe_perf_open(struct trace_event_call *call,
			    struct perf_event *event)
{}

static bool uprobe_perf_filter(struct uprobe_consumer *uc,
				enum uprobe_filter_ctx ctx, struct mm_struct *mm)
{}

static void __uprobe_perf_func(struct trace_uprobe *tu,
			       unsigned long func, struct pt_regs *regs,
			       struct uprobe_cpu_buffer **ucbp)
{}

/* uprobe profile handler */
static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs,
			    struct uprobe_cpu_buffer **ucbp)
{}

static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func,
				struct pt_regs *regs,
				struct uprobe_cpu_buffer **ucbp)
{}

int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type,
			const char **filename, u64 *probe_offset,
			u64 *probe_addr, bool perf_type_tracepoint)
{}
#endif	/* CONFIG_PERF_EVENTS */

static int
trace_uprobe_register(struct trace_event_call *event, enum trace_reg type,
		      void *data)
{}

static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
{}

static int uretprobe_dispatcher(struct uprobe_consumer *con,
				unsigned long func, struct pt_regs *regs)
{}

static struct trace_event_functions uprobe_funcs =;

static struct trace_event_fields uprobe_fields_array[] =;

static inline void init_trace_event_call(struct trace_uprobe *tu)
{}

static int register_uprobe_event(struct trace_uprobe *tu)
{}

static int unregister_uprobe_event(struct trace_uprobe *tu)
{}

#ifdef CONFIG_PERF_EVENTS
struct trace_event_call *
create_local_trace_uprobe(char *name, unsigned long offs,
			  unsigned long ref_ctr_offset, bool is_return)
{}

void destroy_local_trace_uprobe(struct trace_event_call *event_call)
{}
#endif /* CONFIG_PERF_EVENTS */

/* Make a trace interface for controlling probe points */
static __init int init_uprobe_trace(void)
{}

fs_initcall(init_uprobe_trace);