1/*
2 * Copyright (c) 2006-2008 Apple Computer, Inc.  All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24// This must be done *after* any references to Foundation.h!
25#define uint_t  __Solaris_uint_t
26
27#include <pthread.h>
28#include <sys/param.h>
29#include <sys/sysctl.h>
30#include <errno.h>
31#include <stdlib.h>
32
33#include <sys/dtrace.h>
34#include <dtrace.h>
35
36#include <dt_proc.h>
37#include <dt_pid.h>
38
39/*
40 * FIX ME. This is a direct cut & paste from
41 * dt_pid.c. It is probably already out of sync.
42 */
43typedef struct dt_pid_probe {
44	dtrace_hdl_t *dpp_dtp;
45	dt_pcb_t *dpp_pcb;
46	dt_proc_t *dpp_dpr;
47	struct ps_prochandle *dpp_pr;
48	fasttrap_provider_type_t dpp_provider_type;
49	const char *dpp_mod;
50	char *dpp_func;
51	const char *dpp_name;
52	const char *dpp_obj;
53	uintptr_t dpp_pc;
54	size_t dpp_size;
55	Lmid_t dpp_lmid;
56	uint_t dpp_nmatches;
57	uint64_t dpp_stret[4];
58	GElf_Sym dpp_last;
59	uint_t dpp_last_taken;
60} dt_pid_probe_t;
61
62int strisglob(const char *s);
63void dt_proc_bpdisable(dt_proc_t *dpr);
64void dt_proc_bpenable(dt_proc_t *dpr);
65int dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func);
66int dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr, fasttrap_probe_spec_t *ftp, dt_errtag_t tag, const char *fmt, ...);
67
68/*
69 * OBJC provider methods
70 */
71
72static int dt_pid_objc_filt(void *arg, const GElf_Sym *sym, const char *class_name, const char *method_name)
73{
74	dt_pid_probe_t *pp = arg;
75
76        // Handle the class name first.
77	if ((strisglob(pp->dpp_mod) && gmatch(class_name, pp->dpp_mod)) || (strcmp(class_name, pp->dpp_mod) == 0)) {
78                // Now check the method name.
79                if ((strisglob(pp->dpp_func) && gmatch(method_name, pp->dpp_func)) || (strcmp(method_name, pp->dpp_func) == 0)) {
80                        pp->dpp_obj = class_name;
81                        // At this point, we can cheat and use the normal pid probe code.
82                        return dt_pid_per_sym(pp, sym, method_name);
83                }
84        }
85
86	return (0);
87}
88
89int dt_pid_create_objc_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr)
90{
91	dt_pid_probe_t pp;
92	int ret = 0;
93
94	/*
95	 * Disable breakpoints so they don't interfere with our disassembly.
96	 */
97	dt_proc_bpdisable(dpr);
98
99	pp.dpp_dtp = dtp;
100	pp.dpp_dpr = dpr;
101	pp.dpp_pr = dpr->dpr_proc;
102	pp.dpp_pcb = pcb;
103
104	/*
105	 * We can only trace dynamically-linked executables (since we've
106	 * hidden some magic in ld.so.1 as well as libc.so.1).
107	 */
108	prmap_t thread_local_map;
109	if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO, &thread_local_map) == NULL) {
110		return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_DYN,
111				     "process %s has no dyld, and cannot be instrumented",
112				     &pdp->dtpd_provider[3]));
113	}
114
115	pp.dpp_provider_type = DTFTP_PROVIDER_OBJC;
116	pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*";
117	pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*";
118	pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*";
119	pp.dpp_last_taken = 0;
120
121        //
122        // We set up some default values that normally change per module.
123        //
124        pp.dpp_lmid = LM_ID_BASE;
125        pp.dpp_stret[0] = 0;
126        pp.dpp_stret[1] = 0;
127        pp.dpp_stret[2] = 0;
128        pp.dpp_stret[3] = 0;
129
130        /*
131         * We're working in the objc namespace, symbols are in "library, function" style.
132         * We have to look at every symbol in every owner, even without globbing.
133         */
134
135        ret = Pobjc_method_iter(pp.dpp_pr, (proc_objc_f*)dt_pid_objc_filt, &pp);
136
137	dt_proc_bpenable(dpr);
138
139	return (ret);
140}
141
142// Because of the statically cached array, this function is not thread safe.
143int pidFromProcessName(char* name)
144{
145	// Most of this code is from [VMUProcInfo getProcessIds]
146	// The reason we don't call this code directly is because we only get the pids,
147	// and then we have to turn around and construct a VMUProcInfo for each pid to
148	// populate our proc table.
149
150	static struct kinfo_proc *procBuf = NULL;
151	static int numberOfProcs;
152
153	if (procBuf == NULL) {
154		size_t bufSize;
155		int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL};
156		int err;
157
158		// Try to find out how many processes are around so we can
159		// size the buffer appropriately.  sysctl's man page specifically suggests
160		// this approach, and says it returns a bit larger size than needed to handle
161		// any new processes created between then and now.
162
163		err = sysctl(mib, 4, NULL, &bufSize, NULL, 0);
164
165		if((err < 0) && (err != ENOMEM)) {
166			// enomem says we didn't have enough room for the entire buffer.
167			// We don't care about that, we're trying to get the size of a buffer
168			// suitable for getting all the data.
169			perror("Failure calling sysctl to get process list buffer size");
170			return -1;
171		}
172
173		// Now for the real access.  Create the buffer, and grab the
174		// data.
175		procBuf = (struct kinfo_proc *)calloc(1, bufSize);
176
177		if(sysctl(mib, 4, procBuf, &bufSize, NULL, 0) < 0) {
178			//perror("Failure calling sysctl to get proc buf");
179			free(procBuf);
180			return -1;
181		}
182
183		numberOfProcs = (int)(bufSize / (sizeof(struct kinfo_proc)));
184	}
185
186	int i;
187	for (i=0; i<numberOfProcs; i++) {
188		if (strncmp(name, procBuf[i].kp_proc.p_comm, MAXCOMLEN) == 0)
189			return procBuf[i].kp_proc.p_pid;
190	}
191
192	return -1;
193}
194
195