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