4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * #pragma ident "@(#)dtrace_subr.c 1.8 07/06/05 SMI"
33 #include <sys/malloc.h>
35 #include <sys/dtrace.h>
36 #include <sys/dtrace_impl.h>
37 #include <sys/proc_internal.h>
38 #include <kern/debug.h>
39 #include <kern/sched_prim.h>
40 #include <kern/task.h>
43 #include <sys/codesign.h>
48 * APPLE NOTE: Solaris proc_t is the struct.
49 * Darwin's proc_t is a pointer to it.
51 #define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
54 /* Copied from an arch specific dtrace_subr.c. */
55 int (*dtrace_fasttrap_probe_ptr
)(struct regs
*);
58 * Following DTrace hooks are taken from Solaris' dtrace_subr.c
59 * They're assigned in dtrace.c but Darwin never calls them.
61 void (*dtrace_cpu_init
)(processorid_t
);
62 int (*dtrace_modload
)(struct kmod_info
*, uint32_t);
63 int (*dtrace_modunload
)(struct kmod_info
*);
64 void (*dtrace_helpers_cleanup
)(proc_t
*);
65 void (*dtrace_helpers_fork
)(proc_t
*, proc_t
*);
66 void (*dtrace_cpustart_init
)(void);
67 void (*dtrace_cpustart_fini
)(void);
69 void (*dtrace_debugger_init
)(void);
70 void (*dtrace_debugger_fini
)(void);
72 dtrace_vtime_state_t dtrace_vtime_active
= 0;
73 dtrace_cacheid_t dtrace_predcache_id
= DTRACE_CACHEIDNONE
+ 1;
75 void (*dtrace_fasttrap_fork_ptr
)(proc_t
*, proc_t
*);
76 void (*dtrace_fasttrap_exec_ptr
)(proc_t
*);
77 void (*dtrace_fasttrap_exit_ptr
)(proc_t
*);
80 * This function is called by cfork() in the event that it appears that
81 * there may be dtrace tracepoints active in the parent process's address
82 * space. This first confirms the existence of dtrace tracepoints in the
83 * parent process and calls into the fasttrap module to remove the
84 * corresponding tracepoints from the child. By knowing that there are
85 * existing tracepoints, and ensuring they can't be removed, we can rely
86 * on the fasttrap module remaining loaded.
89 dtrace_fasttrap_fork(proc_t
*p
, proc_t
*cp
)
91 if (dtrace_fasttrap_fork_ptr
) {
92 (*dtrace_fasttrap_fork_ptr
)(p
, cp
);
98 * DTrace wait for process execution
100 * This feature is using a list of entries, each entry containing a pointer
101 * on a process description. The description is provided by a client, and it
102 * contains the command we want to wait for along with a reserved space for
103 * the caught process id.
105 * Once an awaited process has been spawned, it will be suspended before
106 * notifying the client. Once the client has been back to userland, it's its
107 * duty to resume the task.
110 lck_mtx_t dtrace_procwaitfor_lock
;
112 typedef struct dtrace_proc_awaited_entry
{
113 struct dtrace_procdesc
*pdesc
;
114 LIST_ENTRY(dtrace_proc_awaited_entry
) entries
;
115 } dtrace_proc_awaited_entry_t
;
117 LIST_HEAD(listhead
, dtrace_proc_awaited_entry
) dtrace_proc_awaited_head
118 = LIST_HEAD_INITIALIZER(dtrace_proc_awaited_head
);
120 void (*dtrace_proc_waitfor_exec_ptr
)(proc_t
*) = NULL
;
123 dtrace_proc_exec_notification(proc_t
*p
) {
124 dtrace_proc_awaited_entry_t
*entry
, *tmp
;
127 ASSERT(p
->p_pid
!= -1);
128 ASSERT(current_task() != p
->task
);
130 lck_mtx_lock(&dtrace_procwaitfor_lock
);
133 * For each entry, if it has not been matched with a process yet we
134 * try to match it with the newly created process. If they match, the
135 * entry is initialized with the process id and the process task is
136 * suspended. Finally, we wake up the client's waiting thread.
138 LIST_FOREACH_SAFE(entry
, &dtrace_proc_awaited_head
, entries
, tmp
) {
139 if ((entry
->pdesc
->p_pid
== -1)
140 && !strncmp(entry
->pdesc
->p_comm
, &p
->p_comm
[0], sizeof(p
->p_comm
)))
142 entry
->pdesc
->p_pid
= p
->p_pid
;
143 task_pidsuspend(p
->task
);
148 lck_mtx_unlock(&dtrace_procwaitfor_lock
);
152 dtrace_proc_waitfor(dtrace_procdesc_t
* pdesc
) {
153 dtrace_proc_awaited_entry_t entry
;
157 ASSERT(pdesc
->p_comm
);
159 lck_mtx_lock(&dtrace_procwaitfor_lock
);
161 /* Initialize and insert the entry, then install the hook. */
164 LIST_INSERT_HEAD(&dtrace_proc_awaited_head
, &entry
, entries
);
165 dtrace_proc_waitfor_exec_ptr
= &dtrace_proc_exec_notification
;
167 /* Sleep until the process has been executed */
168 res
= msleep(&entry
, &dtrace_procwaitfor_lock
, PCATCH
, "dtrace_proc_waitfor", NULL
);
170 /* Remove the entry and the hook if it is not needed anymore. */
171 LIST_REMOVE(&entry
, entries
);
172 if (LIST_EMPTY(&dtrace_proc_awaited_head
))
173 dtrace_proc_waitfor_exec_ptr
= NULL
;
175 lck_mtx_unlock(&dtrace_procwaitfor_lock
);
181 typedef struct dtrace_invop_hdlr
{
182 int (*dtih_func
)(uintptr_t, uintptr_t *, uintptr_t);
183 struct dtrace_invop_hdlr
*dtih_next
;
184 } dtrace_invop_hdlr_t
;
186 dtrace_invop_hdlr_t
*dtrace_invop_hdlr
;
189 dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
192 dtrace_invop(uintptr_t addr
, uintptr_t *stack
, uintptr_t eax
)
194 dtrace_invop_hdlr_t
*hdlr
;
197 for (hdlr
= dtrace_invop_hdlr
; hdlr
!= NULL
; hdlr
= hdlr
->dtih_next
) {
198 if ((rval
= hdlr
->dtih_func(addr
, stack
, eax
)) != 0)
206 dtrace_invop_add(int (*func
)(uintptr_t, uintptr_t *, uintptr_t))
208 dtrace_invop_hdlr_t
*hdlr
;
210 hdlr
= kmem_alloc(sizeof (dtrace_invop_hdlr_t
), KM_SLEEP
);
211 hdlr
->dtih_func
= func
;
212 hdlr
->dtih_next
= dtrace_invop_hdlr
;
213 dtrace_invop_hdlr
= hdlr
;
217 dtrace_invop_remove(int (*func
)(uintptr_t, uintptr_t *, uintptr_t))
219 dtrace_invop_hdlr_t
*hdlr
= dtrace_invop_hdlr
, *prev
= NULL
;
223 panic("attempt to remove non-existent invop handler");
225 if (hdlr
->dtih_func
== func
)
229 hdlr
= hdlr
->dtih_next
;
233 ASSERT(dtrace_invop_hdlr
== hdlr
);
234 dtrace_invop_hdlr
= hdlr
->dtih_next
;
236 ASSERT(dtrace_invop_hdlr
!= hdlr
);
237 prev
->dtih_next
= hdlr
->dtih_next
;
240 kmem_free(hdlr
, sizeof (dtrace_invop_hdlr_t
));
244 * Check if DTrace has been restricted by the current security policy.
247 dtrace_is_restricted(void)
250 if (csr_check(CSR_ALLOW_UNRESTRICTED_DTRACE
) != 0)
258 * Check if the process can be attached.
261 dtrace_can_attach_to_proc(proc_t
*proc
)
264 ASSERT(proc
!= NULL
);
267 if ((cs_entitlement_flags(proc
) & CS_GET_TASK_ALLOW
) == 0)