]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_pcsamples.c
xnu-344.21.74.tar.gz
[apple/xnu.git] / bsd / kern / kern_pcsamples.c
index 68ba7cc973629593de4d1abd964174df7a273563..9a0a3ced59e174ebb6f1ee1d2f7b1d87c8adbc7f 100644 (file)
@@ -3,19 +3,22 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
@@ -37,6 +40,9 @@ unsigned int pc_bufsize      = 0;
 unsigned int pcsample_flags  = 0;
 unsigned int pcsample_enable = 0;
 
+pid_t pc_sample_pid = 0;
+boolean_t pc_trace_frameworks = FALSE;
+
 char pcsample_comm[MAXCOMLEN + 1];
 
 /* Set the default framework boundaries */
@@ -48,6 +54,65 @@ static pid_t global_state_pid = -1;       /* Used to control exclusive use of pc
 extern int pc_trace_buf[];
 extern int pc_trace_cnt;
 
+int
+enable_branch_tracing()
+{
+#ifndef i386
+  struct proc *p;
+  if (-1 != pc_sample_pid) {
+    p = pfind(pc_sample_pid);
+    if (p) {
+      p->p_flag |= P_BTRACE;
+    } 
+  }
+  else {
+    pc_trace_frameworks = TRUE;
+  }
+
+  return 1;
+
+#else
+    return 0;
+#endif
+}
+
+int
+disable_branch_tracing()
+{
+  struct proc *p;
+  switch (pc_sample_pid) {
+    case -1:
+      pc_trace_frameworks = FALSE;
+  break;
+ case 0:
+   break;
+ default:
+   p = pfind(pc_sample_pid);
+   if (p) {
+     p->p_flag &= ~P_BTRACE;
+   }
+   break;
+}
+  clr_be_bit();
+  return 1;
+}
+
+/*
+ * this only works for the current proc as it
+ * is called from context_switch in the scheduler
+ */
+int
+branch_tracing_enabled()
+{
+  struct proc *p = current_proc();
+  if (TRUE == pc_trace_frameworks) return TRUE;
+  if (p) {
+    return (P_BTRACE == (p->p_flag & P_BTRACE));
+  }
+  return 0;
+}
+
+
 void
 add_pcbuffer()
 {
@@ -59,15 +124,6 @@ add_pcbuffer()
        if (!pcsample_enable)
          return;
 
-       if (pcsample_comm[0] != '\0')
-       {
-         /* If command string does not match, then return */
-           curproc = current_proc();
-           if (curproc && 
-               (strncmp(curproc->p_comm, pcsample_comm, sizeof(pcsample_comm))))
-             return;
-       }
-
        for (i=0; i < pc_trace_cnt; i++)
          {
            pc = pc_trace_buf[i];
@@ -90,7 +146,7 @@ add_pcbuffer()
        if ((pc_bufptr + pc_trace_cnt) >= pc_buflast)
          {
            pcsample_enable = 0;
-           (void)clr_be_bit();
+           (void)disable_branch_tracing();
            wakeup(&pcsample_enable);
          }
        return;
@@ -98,7 +154,7 @@ add_pcbuffer()
 
 pcsamples_bootstrap()
 {
-       if (!clr_be_bit())
+        if (!disable_branch_tracing())
             return(ENOTSUP);
 
        pc_bufsize = npcbufs * sizeof(* pc_buffer);
@@ -148,7 +204,10 @@ pcsamples_clear()
        pcsample_beg= 0;
        pcsample_end= 0;
        bzero((void *)pcsample_comm, sizeof(pcsample_comm));
-       (void)clr_be_bit();
+       (void)disable_branch_tracing();
+       pc_sample_pid = 0;
+       pc_trace_frameworks = FALSE;
+
 }
 
 pcsamples_control(name, namelen, where, sizep)
@@ -161,6 +220,7 @@ int ret=0;
 int size=*sizep;
 unsigned int value = name[1];
 pcinfo_t pc_bufinfo;
+pid_t *pidcheck;
 
 pid_t curpid;
 struct proc *p, *curproc;
@@ -234,7 +294,7 @@ struct proc *p, *curproc;
                          {
                            /* Do not wait on the buffer */
                            pcsample_enable = 0;
-                           (void)clr_be_bit();
+                           (void)disable_branch_tracing();
                            ret = pcsamples_read(where, sizep);
                            break;
                          }
@@ -246,9 +306,9 @@ struct proc *p, *curproc;
                        }
 
                        /* Turn on branch tracing */
-                       if (!set_be_bit())
+                       if (!enable_branch_tracing())
                          {
-                           ret = ENOTSUP;;
+                           ret = ENOTSUP;
                            break;
                          }
 
@@ -257,7 +317,7 @@ struct proc *p, *curproc;
 
                        ret = tsleep(&pcsample_enable, PRIBIO | PCATCH, "pcsample", 0);
                        pcsample_enable = 0;
-                       (void)clr_be_bit();
+                       (void)disable_branch_tracing();
 
                        if (ret)
                          {
@@ -298,10 +358,31 @@ struct proc *p, *curproc;
                            break;
                        }
                        bzero((void *)pcsample_comm, sizeof(pcsample_comm));
-                       if (copyin(where, pcsample_comm, size))
-                       {
-                           ret = EINVAL;
-                       }
+                       if (copyin(where, pcsample_comm, size))
+                         {
+                           ret = EINVAL;
+                           break;
+                         }
+
+                       /* Check for command name or pid */
+                       if (pcsample_comm[0] != '\0')
+                         {
+                           ret= EOPNOTSUPP;
+                           break;
+                         }
+                       else
+                         {
+                           if (size != (2 * sizeof(pid_t)))
+                           {
+                             ret = EINVAL;
+                             break;
+                           }
+                           else
+                             {
+                               pidcheck = (pid_t *)pcsample_comm;
+                               pc_sample_pid = pidcheck[1];
+                             }
+                         }
                        break;
                default:
                        ret= EOPNOTSUPP;
@@ -356,6 +437,3 @@ int copycount;
          }
 }
 
-
-
-