1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
/*
* Oracle Linux DTrace.
* Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
#ifndef _DT_PROC_H
#define _DT_PROC_H
#include <signal.h>
#include <time.h>
#include <rtld_db.h>
#include <libproc.h>
#include <dtrace.h>
#include <pthread.h>
#include <dt_list.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_proc {
dt_list_t dpr_list; /* prev/next pointers for lru chain */
struct dt_proc *dpr_hash; /* next pointer for pid hash chain */
dtrace_hdl_t *dpr_hdl; /* back pointer to libdtrace handle */
struct ps_prochandle *dpr_proc; /* proc handle for libproc calls */
char dpr_errmsg[BUFSIZ]; /* error message */
pthread_mutex_t dpr_lock; /* lock around many libproc operations,
and our condition variables */
pthread_t dpr_lock_holder; /* holder of the dpr_lock, if nonzero
lock count */
unsigned long dpr_lock_count_main; /* main-thread dpr_lock count */
unsigned long dpr_lock_count_ctrl; /* ctrl-thread dpr_lock count */
pthread_cond_t dpr_cv; /* cond for startup/stop/quit/done */
pthread_cond_t dpr_msg_cv; /* cond for msgs from main thread */
pthread_t dpr_tid; /* control thread (or zero if none) */
pid_t dpr_pid; /* pid of process */
int dpr_proxy_fd[2]; /* proxy request pipe from main thread */
timer_t dpr_proxy_timer; /* control-thread-signalling timer */
uint_t dpr_refs; /* reference count */
uint8_t dpr_stop; /* stop mask: see flag bits below */
uint8_t dpr_done; /* done flag: ctl thread has exited */
uint8_t dpr_created; /* proc flag: true if we created this
process, false if we grabbed it */
uint8_t dpr_monitoring; /* true if we should background-monitor
the process right now */
uint8_t dpr_ending; /* true in the middle of process death,
when unlocking should null out the
dpr_tid */
uint8_t dpr_notifiable; /* true if we should call notifiers
when this process dies */
uint8_t dpr_awaiting_dlactivity; /* true if a dlopen()/dlclose() has
been seen and the victim ld.so is
not yet in a consistent state */
/*
* Proxying. These structures encode the return type and parameters of
* all libproc functions which are unsafe to call from multiple threads
* for which we provide proxies. The dpr_libproc_rq simply holds the
* address of the currently-executing proxy function (which is private
* to libproc.c, so not interpretable from here). Executing one
* proxy from inside another is not possible, because each proxy
* degenerates to an immediate call if it is executed from the
* process-control thread itself.
*
* Currently proxied requests are proxy_pwait(), proxy_ptrace() and
* dt_proc_continue(): the latter takes no arguments. In all these
* cases, if an exec is detected, dpr_proxy_exec_retry is set on return:
* it is then the proxy's responsibility to rethrow and unwind all the
* way out, destroy and reattach to the libproc structure, and retry
* whatever it was doing.
*
* In addition, communication between the main thread and
* process-control thread also uses this mechanism but does not
* participate in the exec-detection mechanism. This uses requests
* proxy_reattach(), proxy_monitor(), and proxy_quit().
*/
long (*dpr_proxy_rq)();
long dpr_proxy_ret;
long dpr_proxy_exec_retry;
int dpr_proxy_errno;
union {
struct {
enum __ptrace_request request;
pid_t pid;
void *addr;
void *data;
} dpr_ptrace;
struct {
struct ps_prochandle *P;
boolean_t block;
} dpr_pwait;
struct {
boolean_t monitor;
} dpr_monitor;
struct {
int err;
} dpr_quit;
} dpr_proxy_args;
} dt_proc_t;
typedef struct dt_proc_notify {
dt_proc_t *dprn_dpr; /* process associated with the event */
pid_t dprn_pid; /* pid associated with dprn_dpr */
char dprn_errmsg[BUFSIZ]; /* error message */
struct dt_proc_notify *dprn_next; /* next pointer */
} dt_proc_notify_t;
/*
* An opaque handle to a process, for the external API.
*/
typedef struct dtrace_proc {
pid_t pid;
} dtrace_proc_t;
/*
* This is an internal-only flag in the DTRACE_PROC_* space. External API
* callers cannot turn it off.
*/
#define DTRACE_PROC_NOTIFIABLE 0x10 /* true if notifiers must be called */
#define DT_PROC_STOP_IDLE 0x01 /* idle on owner's stop request */
#define DT_PROC_STOP_CREATE 0x02 /* wait on dpr_cv at process exec */
#define DT_PROC_STOP_GRAB 0x04 /* wait on dpr_cv at process grab */
#define DT_PROC_STOP_RESUMING 0x08 /* tell dt_proc_resume() to resume */
#define DT_PROC_STOP_RESUMED 0x10 /* wait on dpr_cv after resume */
#define DT_PROC_STOP_PREINIT 0x20 /* wait on dpr_cv at rtld preinit */
#define DT_PROC_STOP_POSTINIT 0x40 /* wait on dpr_cv at rtld postinit */
#define DT_PROC_STOP_MAIN 0x80 /* wait on dpr_cv at a.out`main() */
typedef struct dt_proc_hash {
pthread_mutex_t dph_lock; /* lock protecting dph_notify list */
dt_proc_notify_t *dph_notify; /* list of pending proc notifications */
dt_list_t dph_lrulist; /* list of dt_proc_t's in lru order */
uint_t dph_lrulim; /* limit on number of procs to hold */
uint_t dph_lrucnt; /* count of cached process handles */
uint_t dph_hashlen; /* size of hash chains array */
dt_proc_t *dph_hash[1]; /* hash chains array */
} dt_proc_hash_t;
extern pid_t dt_proc_grab_lock(dtrace_hdl_t *dtp, pid_t pid, int flags);
extern void dt_proc_release_unlock(dtrace_hdl_t *, pid_t);
extern void dt_proc_lock(dt_proc_t *dpr);
extern void dt_proc_unlock(dt_proc_t *dpr);
extern dt_proc_t *dt_proc_lookup(dtrace_hdl_t *, pid_t);
/*
* Proxies for operations in libproc, respecting the execve-retry protocol.
*/
extern int dt_Plookup_by_addr(dtrace_hdl_t *, pid_t, uintptr_t, const char **,
GElf_Sym *);
extern const prmap_t *dt_Paddr_to_map(dtrace_hdl_t *, pid_t, uintptr_t);
extern const prmap_t *dt_Plmid_to_map(dtrace_hdl_t *, pid_t, Lmid_t,
const char *);
extern const prmap_t *dt_Pname_to_map(dtrace_hdl_t *, pid_t, const char *);
extern char *dt_Pobjname(dtrace_hdl_t *, pid_t, uintptr_t, char *, size_t);
extern int dt_Plmid(dtrace_hdl_t *, pid_t, uintptr_t, Lmid_t *);
extern int dt_Pstate(dtrace_hdl_t *, pid_t);
extern int dt_Pxlookup_by_name(dtrace_hdl_t *, pid_t, Lmid_t, const char *,
const char *, GElf_Sym *, prsyminfo_t *);
extern int dt_Pwritable_mapping(dtrace_hdl_t *, pid_t, uintptr_t);
extern int dt_Psymbol_iter_by_addr(dtrace_hdl_t *, pid_t, const char *, int,
int, proc_sym_f *, void *);
extern int dt_Pobject_iter(dtrace_hdl_t *, pid_t, proc_map_f *, void *);
extern ssize_t dt_Pread(dtrace_hdl_t *, pid_t, void *, size_t, uintptr_t);
extern void dt_proc_hash_create(dtrace_hdl_t *);
extern void dt_proc_hash_destroy(dtrace_hdl_t *);
extern void dt_proc_signal_init(dtrace_hdl_t *);
extern void dt_proc_signal_fini(dtrace_hdl_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PROC_H */
|