/* stapdyn interface header
 * Copyright (C) 2012-2019 Red Hat Inc.
 *
 * This file is part of systemtap, and is free software.  You can
 * redistribute it and/or modify it under the terms of the GNU General
 * Public License (GPL); either version 2, or (at your option) any
 * later version.
 */

#ifndef _STAPDYN_H_
#define _STAPDYN_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <asm/ptrace.h>

#if defined(__aarch64__)

/* <asm/ptrace.h> defines user_pt_regs not pt_regs so clone this from kernel's
 *  arch/arm64/include/asm/ptrace.h */
/*
 * This struct defines the way the registers are stored on the stack during an
 * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for
 * stack alignment). struct user_pt_regs must form a prefix of struct pt_regs.
 */

struct pt_regs {
        union {
                struct user_pt_regs user_regs;
                struct {
                        unsigned long long regs[31];
                        unsigned long long sp;
                        unsigned long long pc;
                        unsigned long long pstate;
                };
        };
        unsigned long long orig_x0;
#ifdef __AARCH64EB__
        unsigned int unused2;
        signed int syscallno;
#else
        signed int syscallno;
        unsigned int unused2;
#endif

        unsigned long long orig_addr_limit;
        unsigned long long unused;     // maintain 16 byte alignment
        unsigned long long stackframe[2];
};
#endif

/* These are declarations of all interfaces that stapdyn may call in the
 * module, either directly or via dyninst in the mutatee.  To maintain
 * compatibility as much as possible, function signatures should not be
 * changed between releases, only deprecated/renamed as necessary.
 *
 * NB: These are organized by the systemtap release in which each was first
 * added, so we can keep some idea of the ABI progression.
 */


/* With -fvisibility=hidden, we have to expose these manually.
 * Using "protected" keeps internal references always internal.  */
#pragma GCC visibility push(protected)


/**** STAP 2.0 : ****/

extern int stp_dyninst_session_init(void);
extern void stp_dyninst_session_exit(void);

extern uint64_t stp_dyninst_target_count(void);
extern const char* stp_dyninst_target_path(uint64_t index);

extern uint64_t stp_dyninst_probe_count(void);
extern uint64_t stp_dyninst_probe_target(uint64_t index);
extern uint64_t stp_dyninst_probe_offset(uint64_t index);
extern uint64_t stp_dyninst_probe_semaphore(uint64_t index);

extern int enter_dyninst_uprobe(uint64_t index, struct pt_regs *regs);

/* This is somewhat of a hack until we can figure out how to build a pt_regs
 * struct directly with stapdyn.  The varargs are all unsigned long, giving
 * first the original PC, then DWARF-ordered registers.  */
extern int enter_dyninst_uprobe_regs(uint64_t index, unsigned long nregs, ...);
extern int enter_dyninst_uprobe_partial_regs(uint64_t index, unsigned long nregs, ...);


/**** STAP 2.1 : ****/

/* uprobes-like flags */
#define STAPDYN_PROBE_FLAG_RETURN	0x1

/* utrace-like flags */
#define STAPDYN_PROBE_FLAG_PROC_BEGIN	0x100
#define STAPDYN_PROBE_FLAG_PROC_END	0x200
#define STAPDYN_PROBE_FLAG_THREAD_BEGIN	0x400
#define STAPDYN_PROBE_FLAG_THREAD_END	0x800

extern uint64_t stp_dyninst_probe_flags(uint64_t index);

extern int enter_dyninst_utrace_probe(uint64_t index, struct pt_regs *regs);

extern const char* stp_dyninst_shm_init(void);
extern int stp_dyninst_shm_connect(const char* name);


/**** STAP 2.2 : ****/

/* The following function is dynamically generated by systemtap, and
 * used by stapdyn to modify global variables at module startup only
 * (that is, *before* running stp_dyninst_session_init()). If the
 * name starts with '@', the name is assumed to be an internal value. */
extern int stp_global_setter(const char *name, const char *value);


/**** STAP 2.3 : ****/

/* Just returns an exit code, for indicating errors in the script.
 * This should be called after stp_dyninst_session_exit (which really
 * should have returned int itself, but now it's a legacy API).  */
int stp_dyninst_exit_status(void);


/**** STAP 2.x : ****/


/* STAPDYN_PROBE_ALL_FLAGS was first added for 2.1, but is placed here so
 * it can continue to be updated with new flags too.  */
#define STAPDYN_PROBE_ALL_FLAGS (uint64_t)(STAPDYN_PROBE_FLAG_RETURN	\
    | STAPDYN_PROBE_FLAG_PROC_BEGIN | STAPDYN_PROBE_FLAG_PROC_END	\
    | STAPDYN_PROBE_FLAG_THREAD_BEGIN | STAPDYN_PROBE_FLAG_THREAD_END)


#pragma GCC visibility pop

#ifdef __cplusplus
}
#endif

#endif /* _STAPDYN_H_ */
