#ifndef _LINUX_UPROBES_H

#include <linux/utrace.h>
#ifndef UTRACE_ACTION_RESUME

/*
 * Assume the kernel is running the 2008 version of utrace.
 * Skip the code in this file and instead use uprobes 2.
 */
#include "../uprobes2/uprobes.h"

#else	/* uprobes 1 (based on original utrace) */

#define _LINUX_UPROBES_H
/*
 * Userspace Probes (UProbes)
 * include/linux/uprobes.h
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright (C) IBM Corporation, 2006
 */
#include <linux/types.h>
#include <linux/list.h>

/* Version 2 includes unmap_u[ret]probe(). */
#define UPROBES_API_VERSION 2

struct pt_regs;

enum uprobe_type {
	UPTY_UPROBE,
	UPTY_URETPROBE
};

/* This is what the user supplies us. */
struct uprobe {
	/*
	 * The pid of the probed process.  Currently, this can be the
	 * thread ID (task->pid) of any active thread in the process.
	 */
	pid_t pid;

	/* Location of the probepoint */
	unsigned long vaddr;

	/* Handler to run when the probepoint is hit */
	void (*handler)(struct uprobe*, struct pt_regs*);

	/*
	 * This function, if non-NULL, will be called upon completion of
	 * an ASYNCHRONOUS registration (i.e., one initiated by a uprobe
	 * handler).  reg = 1 for register, 0 for unregister.  type
	 * specifies the type of [un]register call (uprobe or uretprobe).
	 */
	void (*registration_callback)(struct uprobe *u, int reg,
			enum uprobe_type type, int result);

	/* Reserved for use by uprobes */
	void *kdata;
};

struct uretprobe_instance;

struct uretprobe {
	struct uprobe u;
	void (*handler)(struct uretprobe_instance*, struct pt_regs*);
};

struct uretprobe_instance {
	struct uretprobe *rp;
	unsigned long ret_addr;
	struct hlist_node hlist;
	unsigned long sp;
	unsigned long reserved1;
};

extern int register_uprobe(struct uprobe *u);
extern void unregister_uprobe(struct uprobe *u);
/* For runtime, assume uprobes support includes uretprobes. */
extern int register_uretprobe(struct uretprobe *rp);
extern void unregister_uretprobe(struct uretprobe *rp);
/* For PRs 9940, 6852... */
extern void unmap_uprobe(struct uprobe *u);
extern void unmap_uretprobe(struct uretprobe *rp);
/*
 * Given a program counter, translate it back to the original address
 * if it is the address of the trampoline. sp is the stack pointer for
 * the frame that corresponds to the address.
 *
 * When not called from a uretprobe hander, pass GET_PC_URETPROBE_NONE.
 */
#define GET_PC_URETPROBE_NONE ((struct uretprobe_instance *)-1L)
extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri,
                                   unsigned long pc,
                                   unsigned long sp);
/*
 * This version will do the mapping for an arbitrary task.
 */
extern unsigned long uprobe_get_pc_task(struct task_struct *task,
					unsigned long pc,
					unsigned long sp);

#ifdef UPROBES_IMPLEMENTATION

#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/wait.h>
#include <asm/atomic.h>
#include "uprobes_arch.h"

struct task_struct;
struct utrace_attached_engine;

enum uprobe_probept_state {
	UPROBE_INSERTING,	// process quiescing prior to insertion
	UPROBE_BP_SET,		// breakpoint in place
	UPROBE_REMOVING,	// process quiescing prior to removal
	UPROBE_DISABLED		// removal completed
};

enum uprobe_task_state {
	UPTASK_QUIESCENT,
	UPTASK_SLEEPING,	// used when task may not be able to quiesce
	UPTASK_RUNNING,
	UPTASK_BP_HIT,
	UPTASK_TRAMPOLINE_HIT,
	UPTASK_PRE_SSTEP,
	UPTASK_SSTEP,
	UPTASK_POST_SSTEP
};

#define UPROBE_HASH_BITS 5
#define UPROBE_TABLE_SIZE (1 << UPROBE_HASH_BITS)

/* Used when deciding which instruction slot to steal. */
enum uprobe_slot_state {
	SSOL_FREE,
	SSOL_ASSIGNED,
	SSOL_BEING_STOLEN,
	SSOL_RESERVED		// e.g., for uretprobe trampoline
};

/*
 * For a uprobe_process that uses an SSOL area, there's an array of these
 * objects matching the array of instruction slots in the SSOL area.
 */
struct uprobe_ssol_slot {
	/* The slot in the SSOL area that holds the instruction-copy */
	__user uprobe_opcode_t	*insn;

	enum uprobe_slot_state state;

	/* The probepoint that currently owns this slot */
	struct uprobe_probept *owner;

	/*
	 * Read-locked when slot is in use during single-stepping.
	 * Write-locked by stealing task.
	 */
	struct rw_semaphore rwsem;

	/* Used for LRU heuristics.  If this overflows, it's OK. */
	unsigned long last_used;
};

/*
 * The per-process single-stepping out-of-line (SSOL) area
 */
struct uprobe_ssol_area {
	/* Array of instruction slots in the vma we allocate */
	__user uprobe_opcode_t *insn_area;

	int nslots;
	int nfree;

	/* Array of slot objects, one per instruction slot */
	struct uprobe_ssol_slot *slots;

	/* lock held while finding a free slot */
#ifdef CONFIG_PREMPT_RT
	raw_spinlock_t lock;
#else
	spinlock_t lock;
#endif

	/*
	 * We currently use access_process_vm() to populate instruction
	 * slots.  Calls must be serialized because access_process_vm()
	 * isn't thread-safe.
	 */
	struct mutex populate_mutex;

	/* Next slot to steal */
	int next_slot;

	/* Ensures 2 threads don't try to set up the vma simultaneously. */
	struct mutex setup_mutex;

	/* 1 = we've at least tried.  IS_ERR(insn_area) if we failed. */
	int initialized;
};

/*
 * uprobe_process -- not a user-visible struct.
 * A uprobe_process represents a probed process.  A process can have
 * multiple probepoints (each represented by a uprobe_probept) and
 * one or more threads (each represented by a uprobe_task).
 */
struct uprobe_process {
	/*
	 * rwsem is write-locked for any change to the uprobe_process's
	 * graph (including uprobe_tasks, uprobe_probepts, and uprobe_kimgs) --
	 * e.g., due to probe [un]registration or special events like exit.
	 * It's read-locked during the whole time we process a probepoint hit.
	 */
	struct rw_semaphore rwsem;

	/* Table of uprobe_probepts registered for this process */
	/* TODO: Switch to list_head[] per Ingo. */
	struct hlist_head uprobe_table[UPROBE_TABLE_SIZE];
	int nppt;	/* number of probepoints */

	/* List of uprobe_probepts awaiting insertion or removal */
	struct list_head pending_uprobes;

	/* List of uprobe_tasks in this task group */
	struct list_head thread_list;
	int nthreads;
	int n_quiescent_threads;

	/* this goes on the uproc_table */
	struct hlist_node hlist;

	/*
	 * All threads (tasks) in a process share the same uprobe_process.
	 */
	pid_t tgid;

	/* Threads in SLEEPING state wait here to be roused. */
	wait_queue_head_t waitq;

	/*
	 * We won't free the uprobe_process while...
	 * - any register/unregister operations on it are in progress; or
	 * - uprobe_table[] is not empty; or
	 * - any tasks are SLEEPING in the waitq; or
	 * - any uretprobe_instances are outstanding.
	 * refcount reflects this.  We do NOT ref-count tasks (threads),
	 * since once the last thread has exited, the rest is academic.
	 */
	atomic_t refcount;

	/* Return-probed functions return via this trampoline. */
	__user uprobe_opcode_t *uretprobe_trampoline_addr;

	/*
	 * finished = 1 means the process is execing or the last thread
	 * is exiting, and we're cleaning up the uproc.  If the execed
	 * process is probed, a new uproc will be created.
	 */
	int finished;

	/*
	 * Manages slots for instruction-copies to be single-stepped
	 * out of line.
	 */
	struct uprobe_ssol_area ssol_area;

	/*
	 * 1 to single-step out of line; 0 for inline.  This can drop to
	 * 0 if we can't set up the SSOL area, but never goes from 0 to 1.
	 */
	int sstep_out_of_line;
};

/*
 * uprobe_kimg -- not a user-visible struct.
 * Holds implementation-only per-uprobe data.
 * uprobe->kdata points to this.
 */
struct uprobe_kimg {
	struct uprobe *uprobe;
	struct uprobe_probept *ppt;

	/*
	 * -EBUSY while we're waiting for all threads to quiesce so the
	 * associated breakpoint can be inserted or removed.
	 * 0 if the the insert/remove operation has succeeded, or -errno
	 * otherwise.
	 */
	int status;

	/* on ppt's list */
	struct list_head list;
};

/*
 * uprobe_probept -- not a user-visible struct.
 * A probepoint, at which several uprobes can be registered.
 * Guarded by uproc->rwsem.
 */
struct uprobe_probept {
	/* vaddr copied from (first) uprobe */
	unsigned long vaddr;

	/* The uprobe_kimg(s) associated with this uprobe_probept */
	struct list_head uprobe_list;

	enum uprobe_probept_state state;

	/* Saved opcode (which has been replaced with breakpoint) */
	uprobe_opcode_t opcode;

	/*
	 * Saved original instruction.  This may be modified by
	 * architecture-specific code if the original instruction
	 * can't be single-stepped out of line as-is.
	 */
	uprobe_opcode_t insn[MAX_UINSN_BYTES / sizeof(uprobe_opcode_t)];

	struct uprobe_probept_arch_info arch_info;

	/* The parent uprobe_process */
	struct uprobe_process *uproc;

	/*
	 * ppt goes in the uprobe_process->uprobe_table when registered --
	 * even before the breakpoint has been inserted.
	 */
	struct hlist_node ut_node;

	/*
	 * ppt sits in the uprobe_process->pending_uprobes queue while
	 * awaiting insertion or removal of the breakpoint.
	 */
	struct list_head pd_node;

	/* [un]register_uprobe() waits 'til bkpt inserted/removed. */
	wait_queue_head_t waitq;

	/*
	 * Serialize single-stepping inline, so threads don't clobber
	 * each other swapping the breakpoint instruction in and out.
	 * This helps prevent crashing the probed app, but it does NOT
	 * prevent probe misses while the breakpoint is swapped out.
	 */
	struct mutex ssil_mutex;

	/*
	 * We put the instruction-copy here to single-step it.
	 * We don't own it unless slot->owner points back to us.
	 */
	struct uprobe_ssol_slot *slot;

	/*
	 * Hold this while stealing an insn slot to ensure that no
	 * other thread, having also hit this probepoint, simultaneously
	 * steals a slot for it.
	 */
	struct mutex slot_mutex;
};

/*
 * uprobe_utask -- not a user-visible struct.
 * Corresponds to a thread in a probed process.
 * Guarded by uproc->rwsem.
 */
struct uprobe_task {
	/* Lives in the global utask_table */
	struct hlist_node hlist;

	/* Lives on the thread_list for the uprobe_process */
	struct list_head list;

	/* This is a back pointer to the task_struct for this task */
	struct task_struct *tsk;

	/* The utrace engine for this task */
	struct utrace_attached_engine *engine;

	/* Back pointer to the associated uprobe_process */
	struct uprobe_process *uproc;

	enum uprobe_task_state state;

	/*
	 * quiescing = 1 means this task has been asked to quiesce.
	 * It may not be able to comply immediately if it's hit a bkpt.
	 */
	int quiescing;

	/* Task currently running quiesce_all_threads() */
	struct task_struct *quiesce_primary;

	/* Set before running handlers; cleared after single-stepping. */
	struct uprobe_probept *active_probe;

	/* Saved address of copied original instruction */
	long singlestep_addr;

	struct uprobe_task_arch_info arch_info;

	/*
	 * Unexpected error in probepoint handling has left task's
	 * text or stack corrupted.  Kill task ASAP.
	 */
	int doomed;

	/* LIFO -- active instances */
	struct hlist_head uretprobe_instances;

	/* [un]registrations initiated by handlers must be asynchronous. */
	struct list_head deferred_registrations;

	/* Delay handler-destined signals 'til after single-step done. */
	struct list_head delayed_signals;
};

#ifdef CONFIG_UPROBES_SSOL
static struct uprobe_ssol_slot *uprobe_get_insn_slot(struct uprobe_probept*);
static void uprobe_pre_ssout(struct uprobe_task*, struct uprobe_probept*,
			struct pt_regs*);
static void uprobe_post_ssout(struct uprobe_task*, struct uprobe_probept*,
			struct pt_regs*);
#endif
static int uprobe_emulate_insn(struct pt_regs *regs,
						struct uprobe_probept *ppt);

#endif	/* UPROBES_IMPLEMENTATION */

#endif	/* uprobes 1 (based on original utrace) */

#endif	/* _LINUX_UPROBES_H */
