The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/kern_pcsamples.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 
   26 #include <sys/kdebug.h>
   27 #include <sys/errno.h>
   28 #include <sys/param.h>
   29 #include <sys/proc.h>
   30 #include <sys/vm.h>
   31 #include <sys/sysctl.h>
   32 #include <vm/vm_kern.h>
   33 
   34 unsigned int pc_buftomem = 0;
   35 u_long     * pc_buffer   = 0;   /* buffer that holds each pc */
   36 u_long     * pc_bufptr   = 0;
   37 u_long     * pc_buflast  = 0;
   38 unsigned int npcbufs         = 8192;      /* number of pc entries in buffer */
   39 unsigned int pc_bufsize      = 0;
   40 unsigned int pcsample_flags  = 0;
   41 unsigned int pcsample_enable = 0;
   42 
   43 pid_t pc_sample_pid = 0;
   44 boolean_t pc_trace_frameworks = FALSE;
   45 
   46 char pcsample_comm[MAXCOMLEN + 1];
   47 
   48 /* Set the default framework boundaries */
   49 u_long pcsample_beg    = 0;
   50 u_long pcsample_end    = 0;
   51 
   52 static pid_t global_state_pid = -1;       /* Used to control exclusive use of pc_buffer */
   53 
   54 extern int pc_trace_buf[];
   55 extern int pc_trace_cnt;
   56 
   57 int
   58 enable_branch_tracing()
   59 {
   60 #ifndef i386
   61   struct proc *p;
   62   if (-1 != pc_sample_pid) {
   63     p = pfind(pc_sample_pid);
   64     if (p) {
   65       p->p_flag |= P_BTRACE;
   66     } 
   67   }
   68   else {
   69     pc_trace_frameworks = TRUE;
   70   }
   71 
   72   return 1;
   73 
   74 #else
   75     return 0;
   76 #endif
   77 }
   78 
   79 int
   80 disable_branch_tracing()
   81 {
   82   struct proc *p;
   83   switch (pc_sample_pid) {
   84     case -1:
   85       pc_trace_frameworks = FALSE;
   86   break;
   87  case 0:
   88    break;
   89  default:
   90    p = pfind(pc_sample_pid);
   91    if (p) {
   92      p->p_flag &= ~P_BTRACE;
   93    }
   94    break;
   95 }
   96   clr_be_bit();
   97   return 1;
   98 }
   99 
  100 /*
  101  * this only works for the current proc as it
  102  * is called from context_switch in the scheduler
  103  */
  104 int
  105 branch_tracing_enabled()
  106 {
  107   struct proc *p = current_proc();
  108   if (TRUE == pc_trace_frameworks) return TRUE;
  109   if (p) {
  110     return (P_BTRACE == (p->p_flag & P_BTRACE));
  111   }
  112   return 0;
  113 }
  114 
  115 
  116 void
  117 add_pcbuffer()
  118 {
  119         int      i;
  120         u_long  pc;
  121         struct proc *curproc;
  122         extern unsigned int kdebug_flags;
  123 
  124         if (!pcsample_enable)
  125           return;
  126 
  127         for (i=0; i < pc_trace_cnt; i++)
  128           {
  129             pc = pc_trace_buf[i];
  130             
  131             if ((pcsample_beg <= pc) && (pc < pcsample_end))
  132               {
  133                 if (pc_bufptr > pc_buffer)
  134                   {
  135                     if ( (*(pc_bufptr-1)) == pc )
  136                       continue;   /* Ignore, probably spinning */
  137                   }
  138 
  139                 /* Then the sample is in our range */
  140                 *pc_bufptr = (u_long)pc;
  141                 pc_bufptr++;
  142               }
  143           }
  144 
  145         /* We never wrap the buffer */
  146         if ((pc_bufptr + pc_trace_cnt) >= pc_buflast)
  147           {
  148             pcsample_enable = 0;
  149             (void)disable_branch_tracing();
  150             wakeup(&pcsample_enable);
  151           }
  152         return;
  153 }
  154 
  155 pcsamples_bootstrap()
  156 {
  157         if (!disable_branch_tracing())
  158             return(ENOTSUP);
  159 
  160         pc_bufsize = npcbufs * sizeof(* pc_buffer);
  161         if (kmem_alloc(kernel_map, &pc_buftomem,
  162                        (vm_size_t)pc_bufsize) == KERN_SUCCESS) 
  163           pc_buffer = (u_long *) pc_buftomem;
  164         else 
  165           pc_buffer= (u_long *) 0;
  166 
  167         if (pc_buffer) {
  168                 pc_bufptr = pc_buffer;
  169                 pc_buflast = &pc_bufptr[npcbufs];
  170                 pcsample_enable = 0;
  171                 return(0);
  172         } else {
  173                 pc_bufsize=0;
  174                 return(EINVAL);
  175         }
  176         
  177 }
  178 
  179 pcsamples_reinit()
  180 {
  181 int x;
  182 int ret=0;
  183 
  184         pcsample_enable = 0;
  185 
  186         if (pc_bufsize && pc_buffer)
  187                 kmem_free(kernel_map, (vm_offset_t)pc_buffer, pc_bufsize);
  188 
  189         ret= pcsamples_bootstrap();
  190         return(ret);
  191 }
  192 
  193 pcsamples_clear()
  194 {
  195         /* Clean up the sample buffer, set defaults */ 
  196         global_state_pid = -1;
  197         pcsample_enable = 0;
  198         if(pc_bufsize && pc_buffer)
  199           kmem_free(kernel_map, (vm_offset_t)pc_buffer, pc_bufsize);
  200         pc_buffer   = (u_long *)0;
  201         pc_bufptr   = (u_long *)0;
  202         pc_buflast  = (u_long *)0;
  203         pc_bufsize  = 0;
  204         pcsample_beg= 0;
  205         pcsample_end= 0;
  206         bzero((void *)pcsample_comm, sizeof(pcsample_comm));
  207         (void)disable_branch_tracing();
  208         pc_sample_pid = 0;
  209         pc_trace_frameworks = FALSE;
  210 
  211 }
  212 
  213 pcsamples_control(name, namelen, where, sizep)
  214 int *name;
  215 u_int namelen;
  216 char *where;
  217 size_t *sizep;
  218 {
  219 int ret=0;
  220 int size=*sizep;
  221 unsigned int value = name[1];
  222 pcinfo_t pc_bufinfo;
  223 pid_t *pidcheck;
  224 
  225 pid_t curpid;
  226 struct proc *p, *curproc;
  227 
  228         if (name[0] != PCSAMPLE_GETNUMBUF)
  229           { 
  230             if(curproc = current_proc())
  231               curpid = curproc->p_pid;
  232             else
  233               return (ESRCH);
  234 
  235             if (global_state_pid == -1)
  236               global_state_pid = curpid;
  237             else if (global_state_pid != curpid)
  238               {
  239                 if((p = pfind(global_state_pid)) == NULL)
  240                   {
  241                     /* The global pid no longer exists */
  242                     global_state_pid = curpid;
  243                   }
  244                 else
  245                   {
  246                     /* The global pid exists, deny this request */
  247                     return(EBUSY);
  248                   }
  249               }
  250           }
  251 
  252 
  253         switch(name[0]) {
  254                 case PCSAMPLE_DISABLE:    /* used to disable */
  255                   pcsample_enable=0;
  256                   break;
  257                 case PCSAMPLE_SETNUMBUF:
  258                         /* The buffer size is bounded by a min and max number of samples */
  259                         if (value < pc_trace_cnt) {
  260                              ret=EINVAL;
  261                              break;
  262                         }
  263                         if (value <= MAX_PCSAMPLES)
  264                           /*    npcbufs = value & ~(PC_TRACE_CNT-1); */
  265                           npcbufs = value;
  266                         else
  267                           npcbufs = MAX_PCSAMPLES;
  268                         break;
  269                 case PCSAMPLE_GETNUMBUF:
  270                         if(size < sizeof(pcinfo_t)) {
  271                             ret=EINVAL;
  272                             break;
  273                         }
  274                         pc_bufinfo.npcbufs = npcbufs;
  275                         pc_bufinfo.bufsize = pc_bufsize;
  276                         pc_bufinfo.enable = pcsample_enable;
  277                         pc_bufinfo.pcsample_beg = pcsample_beg;
  278                         pc_bufinfo.pcsample_end = pcsample_end;
  279                         if(copyout (&pc_bufinfo, where, sizeof(pc_bufinfo)))
  280                           {
  281                             ret=EINVAL;
  282                           }
  283                         break;
  284                 case PCSAMPLE_SETUP:
  285                         ret=pcsamples_reinit();
  286                         break;
  287                 case PCSAMPLE_REMOVE:
  288                         pcsamples_clear();
  289                         break;
  290                 case PCSAMPLE_READBUF:
  291                         /* A nonzero value says enable and wait on the buffer */
  292                         /* A zero value says read up the buffer immediately */
  293                         if (value == 0)
  294                           {
  295                             /* Do not wait on the buffer */
  296                             pcsample_enable = 0;
  297                             (void)disable_branch_tracing();
  298                             ret = pcsamples_read(where, sizep);
  299                             break;
  300                           }
  301                         else if ((pc_bufsize <= 0) || (!pc_buffer))
  302                         {
  303                           /* enable only if buffer is initialized */
  304                           ret=EINVAL;
  305                           break;
  306                         }
  307 
  308                         /* Turn on branch tracing */
  309                         if (!enable_branch_tracing())
  310                           {
  311                             ret = ENOTSUP;
  312                             break;
  313                           }
  314 
  315                         /* Enable sampling */
  316                         pcsample_enable = 1;
  317 
  318                         ret = tsleep(&pcsample_enable, PRIBIO | PCATCH, "pcsample", 0);
  319                         pcsample_enable = 0;
  320                         (void)disable_branch_tracing();
  321 
  322                         if (ret)
  323                           {
  324                             /*  Eventually fix this...  if (ret != EINTR) */
  325                             if (ret)
  326                               {
  327                                 /* On errors, except EINTR, we want to cleanup buffer ptrs */
  328                                 /* pc_bufptr = pc_buffer; */
  329                                 *sizep = 0;
  330                               }
  331                           }
  332                         else
  333                           {
  334                             /* The only way to get here is if the buffer is full */
  335                             ret = pcsamples_read(where, sizep);
  336                           }
  337 
  338                         break;
  339                 case PCSAMPLE_SETREG:
  340                         if (size < sizeof(pcinfo_t))
  341                           {
  342                             ret = EINVAL;
  343                             break;
  344                           }
  345                         if (copyin(where, &pc_bufinfo, sizeof(pcinfo_t)))
  346                           {
  347                             ret = EINVAL;
  348                             break;
  349                           }
  350 
  351                         pcsample_beg = pc_bufinfo.pcsample_beg;
  352                         pcsample_end = pc_bufinfo.pcsample_end;
  353                         break;
  354                 case PCSAMPLE_COMM:
  355                         if (!(sizeof(pcsample_comm) > size))
  356                         {
  357                             ret = EINVAL;
  358                             break;
  359                         }
  360                         bzero((void *)pcsample_comm, sizeof(pcsample_comm));
  361                         if (copyin(where, pcsample_comm, size))
  362                           {
  363                             ret = EINVAL;
  364                             break;
  365                           }
  366 
  367                         /* Check for command name or pid */
  368                         if (pcsample_comm[0] != '\0')
  369                           {
  370                             ret= EOPNOTSUPP;
  371                             break;
  372                           }
  373                         else
  374                           {
  375                             if (size != (2 * sizeof(pid_t)))
  376                             {
  377                               ret = EINVAL;
  378                               break;
  379                             }
  380                             else
  381                               {
  382                                 pidcheck = (pid_t *)pcsample_comm;
  383                                 pc_sample_pid = pidcheck[1];
  384                               }
  385                           }
  386                         break;
  387                 default:
  388                         ret= EOPNOTSUPP;
  389                         break;
  390         }
  391         return(ret);
  392 }
  393 
  394 
  395 /* 
  396    This buffer must be read up in one call.
  397    If the buffer isn't big enough to hold
  398    all the samples, it will copy up enough
  399    to fill the buffer and throw the rest away.
  400    This buffer never wraps.
  401 */
  402 pcsamples_read(u_long *buffer, size_t *number)
  403 {
  404 int count=0;
  405 int ret=0;
  406 int copycount;
  407 
  408         count = (*number)/sizeof(u_long);
  409 
  410         if (count && pc_bufsize && pc_buffer)
  411           {
  412               copycount = pc_bufptr - pc_buffer;
  413               
  414               if (copycount <= 0)
  415                 {
  416                   *number = 0;
  417                   return(0);
  418                 }
  419 
  420               if (copycount > count)
  421                 copycount = count;
  422 
  423               /* We actually have data to send up */
  424               if(copyout(pc_buffer, buffer, copycount * sizeof(u_long)))
  425                 {
  426                   *number = 0;
  427                   return(EINVAL);
  428                 }
  429               *number = copycount;
  430               pc_bufptr = pc_buffer;
  431               return(0);
  432           }
  433         else
  434           {
  435             *number = 0;
  436             return(0);
  437           }
  438 }
  439 

Cache object: ab69a3151776ea30cc61ce7bee8103e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.