File: dt_proc.h

package info (click to toggle)
dtrace 2.0.5-1
  • links: PTS
  • area: main
  • in suites: sid
  • size: 24,408 kB
  • sloc: ansic: 61,247; sh: 17,997; asm: 1,717; lex: 947; awk: 754; yacc: 695; perl: 37; sed: 17; makefile: 15
file content (180 lines) | stat: -rw-r--r-- 6,983 bytes parent folder | download
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 */