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/kern/kern_ktrace.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 /*      $NetBSD: kern_ktrace.c,v 1.96.4.1 2006/10/24 16:33:44 ghen Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)kern_ktrace.c       8.5 (Berkeley) 5/14/95
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.96.4.1 2006/10/24 16:33:44 ghen Exp $");
   36 
   37 #include "opt_ktrace.h"
   38 #include "opt_compat_mach.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/proc.h>
   43 #include <sys/file.h>
   44 #include <sys/namei.h>
   45 #include <sys/vnode.h>
   46 #include <sys/kernel.h>
   47 #include <sys/kthread.h>
   48 #include <sys/ktrace.h>
   49 #include <sys/malloc.h>
   50 #include <sys/syslog.h>
   51 #include <sys/filedesc.h>
   52 #include <sys/ioctl.h>
   53 #include <sys/callout.h>
   54 
   55 #include <sys/mount.h>
   56 #include <sys/sa.h>
   57 #include <sys/syscallargs.h>
   58 
   59 #ifdef KTRACE
   60 
   61 /*
   62  * XXX:
   63  *      - need better error reporting?
   64  *      - p->p_tracep access lock.  lock p_lock, lock ktd if !NULL, inc ref.
   65  *      - userland utility to sort ktrace.out by timestamp.
   66  *      - keep minimum information in ktrace_entry when rest of alloc failed.
   67  *      - enlarge ktrace_entry so that small entry won't require additional
   68  *        alloc?
   69  *      - per trace control of configurable parameters.
   70  */
   71 
   72 struct ktrace_entry {
   73         TAILQ_ENTRY(ktrace_entry) kte_list;
   74         struct ktr_header kte_kth;
   75         void *kte_buf;                  /* ktr_buf */
   76 };
   77 
   78 struct ktr_desc {
   79         TAILQ_ENTRY(ktr_desc) ktd_list;
   80         int ktd_flags;
   81 #define KTDF_WAIT               0x0001
   82 #define KTDF_DONE               0x0002
   83 #define KTDF_BLOCKING           0x0004
   84 #define KTDF_INTERACTIVE        0x0008
   85         int ktd_error;
   86 #define KTDE_ENOMEM             0x0001
   87 #define KTDE_ENOSPC             0x0002
   88         int ktd_errcnt;
   89         int ktd_ref;                    /* # of reference */
   90         int ktd_qcount;                 /* # of entry in the queue */
   91 
   92         /*
   93          * Params to control behaviour.
   94          */
   95         int ktd_delayqcnt;              /* # of entry allowed to delay */
   96         int ktd_wakedelay;              /* delay of wakeup in *tick* */
   97         int ktd_intrwakdl;              /* ditto, but when interactive */
   98 
   99         struct file *ktd_fp;            /* trace output file */
  100         struct proc *ktd_proc;          /* our kernel thread */
  101         TAILQ_HEAD(, ktrace_entry) ktd_queue;
  102         struct callout ktd_wakch;       /* delayed wakeup */
  103         struct simplelock ktd_slock;
  104 };
  105 
  106 static void     ktrinitheader(struct ktr_header *, struct proc *, int);
  107 static void     ktrwrite(struct ktr_desc *, struct ktrace_entry *);
  108 static int      ktrace_common(struct proc *, int, int, int, struct file *);
  109 static int      ktrops(struct proc *, struct proc *, int, int,
  110                     struct ktr_desc *);
  111 static int      ktrsetchildren(struct proc *, struct proc *, int, int,
  112                     struct ktr_desc *);
  113 static int      ktrcanset(struct proc *, struct proc *);
  114 static int      ktrsamefile(struct file *, struct file *);
  115 
  116 static struct ktr_desc *
  117                 ktd_lookup(struct file *);
  118 static void     ktdrel(struct ktr_desc *);
  119 static void     ktdref(struct ktr_desc *);
  120 static void     ktraddentry(struct proc *, struct ktrace_entry *, int);
  121 /* Flags for ktraddentry (3rd arg) */
  122 #define KTA_NOWAIT              0x0000
  123 #define KTA_WAITOK              0x0001
  124 #define KTA_LARGE               0x0002
  125 static void     ktefree(struct ktrace_entry *);
  126 static void     ktd_logerrl(struct ktr_desc *, int);
  127 static void     ktd_logerr(struct proc *, int);
  128 static void     ktrace_thread(void *);
  129 
  130 /*
  131  * Default vaules.
  132  */
  133 #define KTD_MAXENTRY            1000    /* XXX: tune */
  134 #define KTD_TIMEOUT             5       /* XXX: tune */
  135 #define KTD_DELAYQCNT           100     /* XXX: tune */
  136 #define KTD_WAKEDELAY           5000    /* XXX: tune */
  137 #define KTD_INTRWAKDL           100     /* XXX: tune */
  138 
  139 /*
  140  * Patchable variables.
  141  */
  142 int ktd_maxentry = KTD_MAXENTRY;        /* max # of entry in the queue */
  143 int ktd_timeout = KTD_TIMEOUT;          /* timeout in seconds */
  144 int ktd_delayqcnt = KTD_DELAYQCNT;      /* # of entry allowed to delay */
  145 int ktd_wakedelay = KTD_WAKEDELAY;      /* delay of wakeup in *ms* */
  146 int ktd_intrwakdl = KTD_INTRWAKDL;      /* ditto, but when interactive */
  147 
  148 static struct simplelock ktdq_slock = SIMPLELOCK_INITIALIZER;
  149 static TAILQ_HEAD(, ktr_desc) ktdq = TAILQ_HEAD_INITIALIZER(ktdq);
  150 
  151 MALLOC_DEFINE(M_KTRACE, "ktrace", "ktrace data buffer");
  152 POOL_INIT(kte_pool, sizeof(struct ktrace_entry), 0, 0, 0,
  153     "ktepl", &pool_allocator_nointr);
  154 
  155 static __inline void
  156 ktd_wakeup(struct ktr_desc *ktd)
  157 {
  158 
  159         callout_stop(&ktd->ktd_wakch);
  160         wakeup(ktd);
  161 }
  162 
  163 static void
  164 ktd_logerrl(struct ktr_desc *ktd, int error)
  165 {
  166 
  167         ktd->ktd_error |= error;
  168         ktd->ktd_errcnt++;
  169 }
  170 
  171 static void
  172 ktd_logerr(struct proc *p, int error)
  173 {
  174         struct ktr_desc *ktd = p->p_tracep;
  175 
  176         if (ktd == NULL)
  177                 return;
  178 
  179         simple_lock(&ktd->ktd_slock);
  180         ktd_logerrl(ktd, error);
  181         simple_unlock(&ktd->ktd_slock);
  182 }
  183 
  184 /*
  185  * Release a reference.  Called with ktd_slock held.
  186  */
  187 void
  188 ktdrel(struct ktr_desc *ktd)
  189 {
  190 
  191         KDASSERT(ktd->ktd_ref != 0);
  192         KASSERT(ktd->ktd_ref > 0);
  193         if (--ktd->ktd_ref <= 0) {
  194                 ktd->ktd_flags |= KTDF_DONE;
  195                 wakeup(ktd);
  196         }
  197         simple_unlock(&ktd->ktd_slock);
  198 }
  199 
  200 void
  201 ktdref(struct ktr_desc *ktd)
  202 {
  203 
  204         simple_lock(&ktd->ktd_slock);
  205         ktd->ktd_ref++;
  206         simple_unlock(&ktd->ktd_slock);
  207 }
  208 
  209 struct ktr_desc *
  210 ktd_lookup(struct file *fp)
  211 {
  212         struct ktr_desc *ktd;
  213 
  214         simple_lock(&ktdq_slock);
  215         for (ktd = TAILQ_FIRST(&ktdq); ktd != NULL;
  216             ktd = TAILQ_NEXT(ktd, ktd_list)) {
  217                 simple_lock(&ktd->ktd_slock);
  218                 if (ktrsamefile(ktd->ktd_fp, fp)) {
  219                         ktd->ktd_ref++;
  220                         simple_unlock(&ktd->ktd_slock);
  221                         break;
  222                 }
  223                 simple_unlock(&ktd->ktd_slock);
  224         }
  225         simple_unlock(&ktdq_slock);
  226         return (ktd);
  227 }
  228 
  229 void
  230 ktraddentry(struct proc *p, struct ktrace_entry *kte, int flags)
  231 {
  232         struct ktr_desc *ktd;
  233 #ifdef DEBUG
  234         struct timeval t;
  235         int s;
  236 #endif
  237 
  238         if (p->p_traceflag & KTRFAC_TRC_EMUL) {
  239                 /* Add emulation trace before first entry for this process */
  240                 p->p_traceflag &= ~KTRFAC_TRC_EMUL;
  241                 ktremul(p);
  242         }
  243 
  244         /*
  245          * Tracing may be canceled while we were sleeping waiting for
  246          * memory.
  247          */
  248         ktd = p->p_tracep;
  249         if (ktd == NULL)
  250                 goto freekte;
  251 
  252         /*
  253          * Bump reference count so that the object will remain while
  254          * we are here.  Note that the trace is controlled by other
  255          * process.
  256          */
  257         ktdref(ktd);
  258 
  259         simple_lock(&ktd->ktd_slock);
  260         if (ktd->ktd_flags & KTDF_DONE)
  261                 goto relktd;
  262 
  263         if (ktd->ktd_qcount > ktd_maxentry) {
  264                 ktd_logerrl(ktd, KTDE_ENOSPC);
  265                 goto relktd;
  266         }
  267         TAILQ_INSERT_TAIL(&ktd->ktd_queue, kte, kte_list);
  268         ktd->ktd_qcount++;
  269         if (ktd->ktd_flags & KTDF_BLOCKING)
  270                 goto skip_sync;
  271 
  272         if (flags & KTA_WAITOK &&
  273             (/* flags & KTA_LARGE */0 || ktd->ktd_flags & KTDF_WAIT ||
  274             ktd->ktd_qcount > ktd_maxentry >> 1))
  275                 /*
  276                  * Sync with writer thread since we're requesting rather
  277                  * big one or many requests are pending.
  278                  */
  279                 do {
  280                         ktd->ktd_flags |= KTDF_WAIT;
  281                         ktd_wakeup(ktd);
  282 #ifdef DEBUG
  283                         s = splclock();
  284                         t = mono_time;
  285                         splx(s);
  286 #endif
  287                         if (ltsleep(&ktd->ktd_flags, PWAIT, "ktrsync",
  288                             ktd_timeout * hz, &ktd->ktd_slock) != 0) {
  289                                 ktd->ktd_flags |= KTDF_BLOCKING;
  290                                 /*
  291                                  * Maybe the writer thread is blocking
  292                                  * completely for some reason, but
  293                                  * don't stop target process forever.
  294                                  */
  295                                 log(LOG_NOTICE, "ktrace timeout\n");
  296                                 break;
  297                         }
  298 #ifdef DEBUG
  299                         s = splclock();
  300                         timersub(&mono_time, &t, &t);
  301                         splx(s);
  302                         if (t.tv_sec > 0)
  303                                 log(LOG_NOTICE,
  304                                     "ktrace long wait: %ld.%06ld\n",
  305                                     t.tv_sec, t.tv_usec);
  306 #endif
  307                 } while (p->p_tracep == ktd &&
  308                     (ktd->ktd_flags & (KTDF_WAIT | KTDF_DONE)) == KTDF_WAIT);
  309         else {
  310                 /* Schedule delayed wakeup */
  311                 if (ktd->ktd_qcount > ktd->ktd_delayqcnt)
  312                         ktd_wakeup(ktd);        /* Wakeup now */
  313                 else if (!callout_pending(&ktd->ktd_wakch))
  314                         callout_reset(&ktd->ktd_wakch,
  315                             ktd->ktd_flags & KTDF_INTERACTIVE ?
  316                             ktd->ktd_intrwakdl : ktd->ktd_wakedelay,
  317                             (void (*)(void *))wakeup, ktd);
  318         }
  319 
  320 skip_sync:
  321         ktdrel(ktd);
  322         return;
  323 
  324 relktd:
  325         ktdrel(ktd);
  326 
  327 freekte:
  328         ktefree(kte);
  329 }
  330 
  331 void
  332 ktefree(struct ktrace_entry *kte)
  333 {
  334         struct ktr_header *kth = &kte->kte_kth;
  335 
  336         if (kth->ktr_len > 0)
  337                 free(kte->kte_buf, M_KTRACE);
  338         pool_put(&kte_pool, kte);
  339 }
  340 
  341 /*
  342  * "deep" compare of two files for the purposes of clearing a trace.
  343  * Returns true if they're the same open file, or if they point at the
  344  * same underlying vnode/socket.
  345  */
  346 
  347 int
  348 ktrsamefile(struct file *f1, struct file *f2)
  349 {
  350 
  351         return ((f1 == f2) ||
  352             ((f1 != NULL) && (f2 != NULL) &&
  353                 (f1->f_type == f2->f_type) &&
  354                 (f1->f_data == f2->f_data)));
  355 }
  356 
  357 void
  358 ktrderef(struct proc *p)
  359 {
  360         struct ktr_desc *ktd = p->p_tracep;
  361 
  362         p->p_traceflag = 0;
  363         if (ktd == NULL)
  364                 return;
  365         p->p_tracep = NULL;
  366 
  367         simple_lock(&ktd->ktd_slock);
  368         wakeup(&ktd->ktd_flags);
  369         ktdrel(ktd);
  370 }
  371 
  372 void
  373 ktradref(struct proc *p)
  374 {
  375         struct ktr_desc *ktd = p->p_tracep;
  376 
  377         ktdref(ktd);
  378 }
  379 
  380 void
  381 ktrinitheader(struct ktr_header *kth, struct proc *p, int type)
  382 {
  383 
  384         (void)memset(kth, 0, sizeof(*kth));
  385         kth->ktr_type = type;
  386         microtime(&kth->ktr_time);
  387         kth->ktr_pid = p->p_pid;
  388         memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN);
  389 }
  390 
  391 void
  392 ktrsyscall(struct proc *p, register_t code, register_t realcode,
  393     const struct sysent *callp, register_t args[])
  394 {
  395         struct ktrace_entry *kte;
  396         struct ktr_header *kth;
  397         struct ktr_syscall *ktp;
  398         register_t *argp;
  399         int argsize;
  400         size_t len;
  401         u_int i;
  402 
  403         if (callp == NULL)
  404                 callp = p->p_emul->e_sysent;
  405 
  406         argsize = callp[code].sy_argsize;
  407 #ifdef _LP64
  408         if (p->p_flag & P_32)
  409                 argsize = argsize << 1;
  410 #endif
  411         len = sizeof(struct ktr_syscall) + argsize;
  412 
  413         p->p_traceflag |= KTRFAC_ACTIVE;
  414         kte = pool_get(&kte_pool, PR_WAITOK);
  415         kth = &kte->kte_kth;
  416         ktrinitheader(kth, p, KTR_SYSCALL);
  417 
  418         ktp = malloc(len, M_KTRACE, M_WAITOK);
  419         ktp->ktr_code = realcode;
  420         ktp->ktr_argsize = argsize;
  421         argp = (register_t *)(ktp + 1);
  422         for (i = 0; i < (argsize / sizeof(*argp)); i++)
  423                 *argp++ = args[i];
  424         kth->ktr_len = len;
  425         kte->kte_buf = ktp;
  426 
  427         ktraddentry(p, kte, KTA_WAITOK);
  428         p->p_traceflag &= ~KTRFAC_ACTIVE;
  429 }
  430 
  431 void
  432 ktrsysret(struct proc *p, register_t code, int error, register_t *retval)
  433 {
  434         struct ktrace_entry *kte;
  435         struct ktr_header *kth;
  436         struct ktr_sysret *ktp;
  437 
  438         p->p_traceflag |= KTRFAC_ACTIVE;
  439         kte = pool_get(&kte_pool, PR_WAITOK);
  440         kth = &kte->kte_kth;
  441         ktrinitheader(kth, p, KTR_SYSRET);
  442 
  443         ktp = malloc(sizeof(struct ktr_sysret), M_KTRACE, M_WAITOK);
  444         ktp->ktr_code = code;
  445         ktp->ktr_eosys = 0;                     /* XXX unused */
  446         ktp->ktr_error = error;
  447         ktp->ktr_retval = retval ? retval[0] : 0;
  448         ktp->ktr_retval_1 = retval ? retval[1] : 0;
  449 
  450         kth->ktr_len = sizeof(struct ktr_sysret);
  451         kte->kte_buf = ktp;
  452 
  453         ktraddentry(p, kte, KTA_WAITOK);
  454         p->p_traceflag &= ~KTRFAC_ACTIVE;
  455 }
  456 
  457 /*
  458  * XXX: ndp->ni_pathlen should be passed.
  459  */
  460 void
  461 ktrnamei(struct proc *p, char *path)
  462 {
  463 
  464         ktrkmem(p, KTR_NAMEI, path, strlen(path));
  465 }
  466 
  467 void
  468 ktremul(struct proc *p)
  469 {
  470         const char *emul = p->p_emul->e_name;
  471 
  472         ktrkmem(p, KTR_EMUL, emul, strlen(emul));
  473 }
  474 
  475 void
  476 ktrkmem(struct proc *p, int type, const void *buf, size_t len)
  477 {
  478         struct ktrace_entry *kte;
  479         struct ktr_header *kth;
  480 
  481         p->p_traceflag |= KTRFAC_ACTIVE;
  482         kte = pool_get(&kte_pool, PR_WAITOK);
  483         kth = &kte->kte_kth;
  484         ktrinitheader(kth, p, type);
  485 
  486         kth->ktr_len = len;
  487         kte->kte_buf = malloc(len, M_KTRACE, M_WAITOK);
  488         memcpy(kte->kte_buf, buf, len);
  489 
  490         ktraddentry(p, kte, KTA_WAITOK);
  491         p->p_traceflag &= ~KTRFAC_ACTIVE;
  492 }
  493 
  494 void
  495 ktrgenio(struct proc *p, int fd, enum uio_rw rw, struct iovec *iov,
  496     int len, int error)
  497 {
  498         struct ktrace_entry *kte;
  499         struct ktr_header *kth;
  500         struct ktr_genio *ktp;
  501         caddr_t cp;
  502         int resid = len, cnt;
  503         int buflen;
  504 
  505         if (error)
  506                 return;
  507 
  508         p->p_traceflag |= KTRFAC_ACTIVE;
  509 
  510 next:
  511         buflen = min(PAGE_SIZE, resid + sizeof(struct ktr_genio));
  512 
  513         kte = pool_get(&kte_pool, PR_WAITOK);
  514         kth = &kte->kte_kth;
  515         ktrinitheader(kth, p, KTR_GENIO);
  516 
  517         ktp = malloc(buflen, M_KTRACE, M_WAITOK);
  518         ktp->ktr_fd = fd;
  519         ktp->ktr_rw = rw;
  520 
  521         kte->kte_buf = ktp;
  522 
  523         cp = (caddr_t)(ktp + 1);
  524         buflen -= sizeof(struct ktr_genio);
  525         kth->ktr_len = sizeof(struct ktr_genio);
  526 
  527         while (buflen > 0) {
  528                 cnt = min(iov->iov_len, buflen);
  529                 if (copyin(iov->iov_base, cp, cnt) != 0)
  530                         goto out;
  531                 kth->ktr_len += cnt;
  532                 buflen -= cnt;
  533                 resid -= cnt;
  534                 iov->iov_len -= cnt;
  535                 if (iov->iov_len == 0)
  536                         iov++;
  537                 else
  538                         iov->iov_base = (caddr_t)iov->iov_base + cnt;
  539         }
  540 
  541         /*
  542          * Don't push so many entry at once.  It will cause kmem map
  543          * shortage.
  544          */
  545         ktraddentry(p, kte, KTA_WAITOK | KTA_LARGE);
  546         if (resid > 0) {
  547 #if 0 /* XXX NJWLWP */
  548                 KDASSERT(p->p_cpu != NULL);
  549                 KDASSERT(p->p_cpu == curcpu());
  550 #endif
  551                 /* XXX NJWLWP */
  552                 if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
  553                         preempt(1);
  554 
  555                 goto next;
  556         }
  557 
  558         p->p_traceflag &= ~KTRFAC_ACTIVE;
  559         return;
  560 
  561 out:
  562         ktefree(kte);
  563         p->p_traceflag &= ~KTRFAC_ACTIVE;
  564 }
  565 
  566 void
  567 ktrpsig(struct proc *p, int sig, sig_t action, const sigset_t *mask,
  568     const ksiginfo_t *ksi)
  569 {
  570         struct ktrace_entry *kte;
  571         struct ktr_header *kth;
  572         struct {
  573                 struct ktr_psig kp;
  574                 siginfo_t       si;
  575         } *kbuf;
  576 
  577         p->p_traceflag |= KTRFAC_ACTIVE;
  578         kte = pool_get(&kte_pool, PR_WAITOK);
  579         kth = &kte->kte_kth;
  580         ktrinitheader(kth, p, KTR_PSIG);
  581 
  582         kbuf = malloc(sizeof(*kbuf), M_KTRACE, M_WAITOK);
  583         kbuf->kp.signo = (char)sig;
  584         kbuf->kp.action = action;
  585         kbuf->kp.mask = *mask;
  586         kte->kte_buf = kbuf;
  587         if (ksi) {
  588                 kbuf->kp.code = KSI_TRAPCODE(ksi);
  589                 (void)memset(&kbuf->si, 0, sizeof(kbuf->si));
  590                 kbuf->si._info = ksi->ksi_info;
  591                 kth->ktr_len = sizeof(*kbuf);
  592         } else {
  593                 kbuf->kp.code = 0;
  594                 kth->ktr_len = sizeof(struct ktr_psig);
  595         }
  596 
  597         ktraddentry(p, kte, KTA_WAITOK);
  598         p->p_traceflag &= ~KTRFAC_ACTIVE;
  599 }
  600 
  601 void
  602 ktrcsw(struct proc *p, int out, int user)
  603 {
  604         struct ktrace_entry *kte;
  605         struct ktr_header *kth;
  606         struct ktr_csw *kc;
  607 
  608         p->p_traceflag |= KTRFAC_ACTIVE;
  609 
  610         /*
  611          * We can't sleep if we're already going to sleep (if original
  612          * condition is met during sleep, we hang up).
  613          */
  614         kte = pool_get(&kte_pool, out ? PR_NOWAIT : PR_WAITOK);
  615         if (kte == NULL) {
  616                 ktd_logerr(p, KTDE_ENOMEM);
  617                 goto out;
  618         }
  619         kth = &kte->kte_kth;
  620         ktrinitheader(kth, p, KTR_CSW);
  621 
  622         kc = malloc(sizeof(struct ktr_csw), M_KTRACE,
  623             out ? M_NOWAIT : M_WAITOK);
  624         if (kc == NULL) {
  625                 ktd_logerr(p, KTDE_ENOMEM);
  626                 goto free_kte;
  627         }
  628         kc->out = out;
  629         kc->user = user;
  630         kth->ktr_len = sizeof(struct ktr_csw);
  631         kte->kte_buf = kc;
  632 
  633         ktraddentry(p, kte, out ? KTA_NOWAIT : KTA_WAITOK);
  634         p->p_traceflag &= ~KTRFAC_ACTIVE;
  635         return;
  636 
  637 free_kte:
  638         pool_put(&kte_pool, kte);
  639 out:
  640         p->p_traceflag &= ~KTRFAC_ACTIVE;
  641 }
  642 
  643 int
  644 ktruser(struct proc *p, const char *id, void *addr, size_t len, int ustr)
  645 {
  646         struct ktrace_entry *kte;
  647         struct ktr_header *kth;
  648         struct ktr_user *ktp;
  649         caddr_t user_dta;
  650         int error;
  651 
  652         if (len > KTR_USER_MAXLEN)
  653                 return ENOSPC;
  654 
  655         p->p_traceflag |= KTRFAC_ACTIVE;
  656         kte = pool_get(&kte_pool, PR_WAITOK);
  657         kth = &kte->kte_kth;
  658         ktrinitheader(kth, p, KTR_USER);
  659 
  660         ktp = malloc(sizeof(struct ktr_user) + len, M_KTRACE, M_WAITOK);
  661         if (ustr) {
  662                 if (copyinstr(id, ktp->ktr_id, KTR_USER_MAXIDLEN, NULL) != 0)
  663                         ktp->ktr_id[0] = '\0';
  664         } else
  665                 strncpy(ktp->ktr_id, id, KTR_USER_MAXIDLEN);
  666         ktp->ktr_id[KTR_USER_MAXIDLEN-1] = '\0';
  667 
  668         user_dta = (caddr_t)(ktp + 1);
  669         if ((error = copyin(addr, (void *)user_dta, len)) != 0)
  670                 len = 0;
  671 
  672         kth->ktr_len = sizeof(struct ktr_user) + len;
  673         kte->kte_buf = ktp;
  674 
  675         ktraddentry(p, kte, KTA_WAITOK);
  676         p->p_traceflag &= ~KTRFAC_ACTIVE;
  677         return error;
  678 }
  679 
  680 void
  681 ktrmmsg(struct proc *p, const void *msgh, size_t size)
  682 {
  683 
  684         ktrkmem(p, KTR_MMSG, msgh, size);
  685 }
  686 
  687 void
  688 ktrmool(struct proc *p, const void *kaddr, size_t size, const void *uaddr)
  689 {
  690         struct ktrace_entry *kte;
  691         struct ktr_header *kth;
  692         struct ktr_mool *kp;
  693         struct ktr_mool *buf;
  694 
  695         p->p_traceflag |= KTRFAC_ACTIVE;
  696         kte = pool_get(&kte_pool, PR_WAITOK);
  697         kth = &kte->kte_kth;
  698         ktrinitheader(kth, p, KTR_MOOL);
  699 
  700         kp = malloc(size + sizeof(*kp), M_KTRACE, M_WAITOK);
  701         kp->uaddr = uaddr;
  702         kp->size = size;
  703         buf = kp + 1; /* Skip uaddr and size */
  704         (void)memcpy(buf, kaddr, size);
  705 
  706         kth->ktr_len = size + sizeof(*kp);
  707         kte->kte_buf = kp;
  708 
  709         ktraddentry(p, kte, KTA_WAITOK);
  710         p->p_traceflag &= ~KTRFAC_ACTIVE;
  711 }
  712 
  713 
  714 /* Interface and common routines */
  715 
  716 int
  717 ktrace_common(struct proc *curp, int ops, int facs, int pid, struct file *fp)
  718 {
  719         struct proc *p;
  720         struct pgrp *pg;
  721         struct ktr_desc *ktd = NULL;
  722         int ret = 0;
  723         int error = 0;
  724         int descend;
  725 
  726         curp->p_traceflag |= KTRFAC_ACTIVE;
  727         descend = ops & KTRFLAG_DESCEND;
  728         facs = facs & ~((unsigned) KTRFAC_ROOT);
  729 
  730         switch (KTROP(ops)) {
  731 
  732         case KTROP_CLEARFILE:
  733                 /*
  734                  * Clear all uses of the tracefile
  735                  */
  736 
  737                 ktd = ktd_lookup(fp);
  738                 if (ktd == NULL)
  739                         goto done;
  740 
  741                 proclist_lock_read();
  742                 PROCLIST_FOREACH(p, &allproc) {
  743                         if (p->p_tracep == ktd) {
  744                                 if (ktrcanset(curp, p))
  745                                         ktrderef(p);
  746                                 else
  747                                         error = EPERM;
  748                         }
  749                 }
  750                 proclist_unlock_read();
  751                 goto done;
  752 
  753         case KTROP_SET:
  754                 ktd = ktd_lookup(fp);
  755                 if (ktd == NULL) {
  756                         ktd = malloc(sizeof(struct ktr_desc),
  757                             M_KTRACE, M_WAITOK);
  758                         TAILQ_INIT(&ktd->ktd_queue);
  759                         simple_lock_init(&ktd->ktd_slock);
  760                         callout_init(&ktd->ktd_wakch);
  761                         ktd->ktd_flags = ktd->ktd_qcount =
  762                             ktd->ktd_error = ktd->ktd_errcnt = 0;
  763                         ktd->ktd_ref = 1;
  764                         ktd->ktd_delayqcnt = ktd_delayqcnt;
  765                         ktd->ktd_wakedelay = mstohz(ktd_wakedelay);
  766                         ktd->ktd_intrwakdl = mstohz(ktd_intrwakdl);
  767                         /*
  768                          * XXX: not correct.  needs an way to detect
  769                          * whether ktruss or ktrace.
  770                          */
  771                         if (fp->f_type == DTYPE_PIPE)
  772                                 ktd->ktd_flags |= KTDF_INTERACTIVE;
  773 
  774                         error = kthread_create1(ktrace_thread, ktd,
  775                             &ktd->ktd_proc, "ktr %p", ktd);
  776                         if (error != 0) {
  777                                 free(ktd, M_KTRACE);
  778                                 goto done;
  779                         }
  780 
  781                         simple_lock(&fp->f_slock);
  782                         fp->f_count++;
  783                         simple_unlock(&fp->f_slock);
  784                         ktd->ktd_fp = fp;
  785 
  786                         simple_lock(&ktdq_slock);
  787                         TAILQ_INSERT_TAIL(&ktdq, ktd, ktd_list);
  788                         simple_unlock(&ktdq_slock);
  789                 }
  790                 break;
  791 
  792         case KTROP_CLEAR:
  793                 break;
  794         }
  795 
  796         /*
  797          * need something to (un)trace (XXX - why is this here?)
  798          */
  799         if (!facs) {
  800                 error = EINVAL;
  801                 goto done;
  802         }
  803 
  804         /*
  805          * do it
  806          */
  807         if (pid < 0) {
  808                 /*
  809                  * by process group
  810                  */
  811                 pg = pg_find(-pid, PFIND_UNLOCK_FAIL);
  812                 if (pg == NULL) {
  813                         error = ESRCH;
  814                         goto done;
  815                 }
  816                 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
  817                         if (descend)
  818                                 ret |= ktrsetchildren(curp, p, ops, facs, ktd);
  819                         else
  820                                 ret |= ktrops(curp, p, ops, facs, ktd);
  821                 }
  822 
  823         } else {
  824                 /*
  825                  * by pid
  826                  */
  827                 p = p_find(pid, PFIND_UNLOCK_FAIL);
  828                 if (p == NULL) {
  829                         error = ESRCH;
  830                         goto done;
  831                 }
  832                 if (descend)
  833                         ret |= ktrsetchildren(curp, p, ops, facs, ktd);
  834                 else
  835                         ret |= ktrops(curp, p, ops, facs, ktd);
  836         }
  837         proclist_unlock_read(); /* taken by p{g}_find */
  838         if (!ret)
  839                 error = EPERM;
  840 done:
  841         if (ktd != NULL) {
  842                 if (error != 0) {
  843                         /*
  844                          * Wakeup the thread so that it can be die if we
  845                          * can't trace any process.
  846                          */
  847                         ktd_wakeup(ktd);
  848                 }
  849                 if (KTROP(ops) == KTROP_SET || KTROP(ops) == KTROP_CLEARFILE) {
  850                             simple_lock(&ktd->ktd_slock);
  851                             ktdrel(ktd);
  852                 }
  853         }
  854         curp->p_traceflag &= ~KTRFAC_ACTIVE;
  855         return (error);
  856 }
  857 
  858 /*
  859  * fktrace system call
  860  */
  861 /* ARGSUSED */
  862 int
  863 sys_fktrace(struct lwp *l, void *v, register_t *retval)
  864 {
  865         struct sys_fktrace_args /* {
  866                 syscallarg(int) fd;
  867                 syscallarg(int) ops;
  868                 syscallarg(int) facs;
  869                 syscallarg(int) pid;
  870         } */ *uap = v;
  871         struct proc *curp = l->l_proc;
  872         struct file *fp = NULL;
  873         struct filedesc *fdp = curp->p_fd;
  874         int error;
  875 
  876         if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  877                 return (EBADF);
  878 
  879         FILE_USE(fp);
  880 
  881         if ((fp->f_flag & FWRITE) == 0)
  882                 error = EBADF;
  883         else
  884                 error = ktrace_common(curp, SCARG(uap, ops),
  885                     SCARG(uap, facs), SCARG(uap, pid), fp);
  886 
  887         FILE_UNUSE(fp, curp);
  888 
  889         return error;
  890 }
  891 
  892 /*
  893  * ktrace system call
  894  */
  895 /* ARGSUSED */
  896 int
  897 sys_ktrace(struct lwp *l, void *v, register_t *retval)
  898 {
  899         struct sys_ktrace_args /* {
  900                 syscallarg(const char *) fname;
  901                 syscallarg(int) ops;
  902                 syscallarg(int) facs;
  903                 syscallarg(int) pid;
  904         } */ *uap = v;
  905         struct proc *curp = l->l_proc;
  906         struct vnode *vp = NULL;
  907         struct file *fp = NULL;
  908         int fd;
  909         int ops = SCARG(uap, ops);
  910         int error = 0;
  911         struct nameidata nd;
  912 
  913         ops = KTROP(ops) | (ops & KTRFLAG_DESCEND);
  914 
  915         curp->p_traceflag |= KTRFAC_ACTIVE;
  916         if ((ops & KTROP_CLEAR) == 0) {
  917                 /*
  918                  * an operation which requires a file argument.
  919                  */
  920                 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
  921                     curp);
  922                 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
  923                         curp->p_traceflag &= ~KTRFAC_ACTIVE;
  924                         return (error);
  925                 }
  926                 vp = nd.ni_vp;
  927                 VOP_UNLOCK(vp, 0);
  928                 if (vp->v_type != VREG) {
  929                         (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
  930                         curp->p_traceflag &= ~KTRFAC_ACTIVE;
  931                         return (EACCES);
  932                 }
  933                 /*
  934                  * XXX This uses up a file descriptor slot in the
  935                  * tracing process for the duration of this syscall.
  936                  * This is not expected to be a problem.  If
  937                  * falloc(NULL, ...) DTRT we could skip that part, but
  938                  * that would require changing its interface to allow
  939                  * the caller to pass in a ucred..
  940                  *
  941                  * This will FILE_USE the fp it returns, if any.
  942                  * Keep it in use until we return.
  943                  */
  944                 if ((error = falloc(curp, &fp, &fd)) != 0)
  945                         goto done;
  946 
  947                 fp->f_flag = FWRITE;
  948                 fp->f_type = DTYPE_VNODE;
  949                 fp->f_ops = &vnops;
  950                 fp->f_data = (caddr_t)vp;
  951                 FILE_SET_MATURE(fp);
  952                 vp = NULL;
  953         }
  954         error = ktrace_common(curp, SCARG(uap, ops), SCARG(uap, facs),
  955             SCARG(uap, pid), fp);
  956 done:
  957         if (vp != NULL)
  958                 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
  959         if (fp != NULL) {
  960                 FILE_UNUSE(fp, curp);   /* release file */
  961                 fdrelease(curp, fd);    /* release fd table slot */
  962         }
  963         return (error);
  964 }
  965 
  966 int
  967 ktrops(struct proc *curp, struct proc *p, int ops, int facs,
  968     struct ktr_desc *ktd)
  969 {
  970 
  971         if (!ktrcanset(curp, p))
  972                 return (0);
  973         if (KTROP(ops) == KTROP_SET) {
  974                 if (p->p_tracep != ktd) {
  975                         /*
  976                          * if trace file already in use, relinquish
  977                          */
  978                         ktrderef(p);
  979                         p->p_tracep = ktd;
  980                         ktradref(p);
  981                 }
  982                 p->p_traceflag |= facs;
  983                 if (curp->p_ucred->cr_uid == 0)
  984                         p->p_traceflag |= KTRFAC_ROOT;
  985         } else {
  986                 /* KTROP_CLEAR */
  987                 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
  988                         /* no more tracing */
  989                         ktrderef(p);
  990                 }
  991         }
  992 
  993         /*
  994          * Emit an emulation record, every time there is a ktrace
  995          * change/attach request.
  996          */
  997         if (KTRPOINT(p, KTR_EMUL))
  998                 p->p_traceflag |= KTRFAC_TRC_EMUL;
  999 #ifdef __HAVE_SYSCALL_INTERN
 1000         (*p->p_emul->e_syscall_intern)(p);
 1001 #endif
 1002 
 1003         return (1);
 1004 }
 1005 
 1006 int
 1007 ktrsetchildren(struct proc *curp, struct proc *top, int ops, int facs,
 1008     struct ktr_desc *ktd)
 1009 {
 1010         struct proc *p;
 1011         int ret = 0;
 1012 
 1013         p = top;
 1014         for (;;) {
 1015                 ret |= ktrops(curp, p, ops, facs, ktd);
 1016                 /*
 1017                  * If this process has children, descend to them next,
 1018                  * otherwise do any siblings, and if done with this level,
 1019                  * follow back up the tree (but not past top).
 1020                  */
 1021                 if (LIST_FIRST(&p->p_children) != NULL) {
 1022                         p = LIST_FIRST(&p->p_children);
 1023                         continue;
 1024                 }
 1025                 for (;;) {
 1026                         if (p == top)
 1027                                 return (ret);
 1028                         if (LIST_NEXT(p, p_sibling) != NULL) {
 1029                                 p = LIST_NEXT(p, p_sibling);
 1030                                 break;
 1031                         }
 1032                         p = p->p_pptr;
 1033                 }
 1034         }
 1035         /*NOTREACHED*/
 1036 }
 1037 
 1038 void
 1039 ktrwrite(struct ktr_desc *ktd, struct ktrace_entry *kte)
 1040 {
 1041         struct uio auio;
 1042         struct iovec aiov[64], *iov;
 1043         struct ktrace_entry *top = kte;
 1044         struct ktr_header *kth;
 1045         struct file *fp = ktd->ktd_fp;
 1046         struct proc *p;
 1047         int error;
 1048 
 1049 next:
 1050         auio.uio_iov = iov = &aiov[0];
 1051         auio.uio_offset = 0;
 1052         auio.uio_segflg = UIO_SYSSPACE;
 1053         auio.uio_rw = UIO_WRITE;
 1054         auio.uio_resid = 0;
 1055         auio.uio_iovcnt = 0;
 1056         auio.uio_procp = NULL;
 1057         do {
 1058                 kth = &kte->kte_kth;
 1059                 iov->iov_base = (caddr_t)kth;
 1060                 iov++->iov_len = sizeof(struct ktr_header);
 1061                 auio.uio_resid += sizeof(struct ktr_header);
 1062                 auio.uio_iovcnt++;
 1063                 if (kth->ktr_len > 0) {
 1064                         iov->iov_base = kte->kte_buf;
 1065                         iov++->iov_len = kth->ktr_len;
 1066                         auio.uio_resid += kth->ktr_len;
 1067                         auio.uio_iovcnt++;
 1068                 }
 1069         } while ((kte = TAILQ_NEXT(kte, kte_list)) != NULL &&
 1070             auio.uio_iovcnt < sizeof(aiov) / sizeof(aiov[0]) - 1);
 1071 
 1072 again:
 1073         simple_lock(&fp->f_slock);
 1074         FILE_USE(fp);
 1075         error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio,
 1076             fp->f_cred, FOF_UPDATE_OFFSET);
 1077         FILE_UNUSE(fp, NULL);
 1078         switch (error) {
 1079 
 1080         case 0:
 1081                 if (auio.uio_resid > 0)
 1082                         goto again;
 1083                 if (kte != NULL)
 1084                         goto next;
 1085                 break;
 1086 
 1087         case EWOULDBLOCK:
 1088                 preempt(1);
 1089                 goto again;
 1090 
 1091         default:
 1092                 /*
 1093                  * If error encountered, give up tracing on this
 1094                  * vnode.  Don't report EPIPE as this can easily
 1095                  * happen with fktrace()/ktruss.
 1096                  */
 1097 #ifndef DEBUG
 1098                 if (error != EPIPE)
 1099 #endif
 1100                         log(LOG_NOTICE,
 1101                             "ktrace write failed, errno %d, tracing stopped\n",
 1102                             error);
 1103                 proclist_lock_read();
 1104                 PROCLIST_FOREACH(p, &allproc) {
 1105                         if (p->p_tracep == ktd)
 1106                                 ktrderef(p);
 1107                 }
 1108                 proclist_unlock_read();
 1109         }
 1110 
 1111         while ((kte = top) != NULL) {
 1112                 top = TAILQ_NEXT(top, kte_list);
 1113                 ktefree(kte);
 1114         }
 1115 }
 1116 
 1117 void
 1118 ktrace_thread(void *arg)
 1119 {
 1120         struct ktr_desc *ktd = arg;
 1121         struct file *fp = ktd->ktd_fp;
 1122         struct ktrace_entry *kte;
 1123         int ktrerr, errcnt;
 1124 
 1125         for (;;) {
 1126                 simple_lock(&ktd->ktd_slock);
 1127                 kte = TAILQ_FIRST(&ktd->ktd_queue);
 1128                 if (kte == NULL) {
 1129                         if (ktd->ktd_flags & KTDF_WAIT) {
 1130                                 ktd->ktd_flags &= ~(KTDF_WAIT | KTDF_BLOCKING);
 1131                                 wakeup(&ktd->ktd_flags);
 1132                         }
 1133                         if (ktd->ktd_ref == 0)
 1134                                 break;
 1135                         ltsleep(ktd, PWAIT | PNORELOCK, "ktrwait", 0,
 1136                             &ktd->ktd_slock);
 1137                         continue;
 1138                 }
 1139                 TAILQ_INIT(&ktd->ktd_queue);
 1140                 ktd->ktd_qcount = 0;
 1141                 ktrerr = ktd->ktd_error;
 1142                 errcnt = ktd->ktd_errcnt;
 1143                 ktd->ktd_error = ktd->ktd_errcnt = 0;
 1144                 simple_unlock(&ktd->ktd_slock);
 1145 
 1146                 if (ktrerr) {
 1147                         log(LOG_NOTICE,
 1148                             "ktrace failed, fp %p, error 0x%x, total %d\n",
 1149                             fp, ktrerr, errcnt);
 1150                 }
 1151                 ktrwrite(ktd, kte);
 1152         }
 1153         simple_unlock(&ktd->ktd_slock);
 1154 
 1155         simple_lock(&ktdq_slock);
 1156         TAILQ_REMOVE(&ktdq, ktd, ktd_list);
 1157         simple_unlock(&ktdq_slock);
 1158 
 1159         simple_lock(&fp->f_slock);
 1160         FILE_USE(fp);
 1161 
 1162         /*
 1163          * ktrace file descriptor can't be watched (are not visible to
 1164          * userspace), so no kqueue stuff here
 1165          * XXX: The above comment is wrong, because the fktrace file
 1166          * descriptor is available in userland.
 1167          */
 1168         closef(fp, NULL);
 1169 
 1170         callout_stop(&ktd->ktd_wakch);
 1171         free(ktd, M_KTRACE);
 1172 
 1173         kthread_exit(0);
 1174 }
 1175 
 1176 /*
 1177  * Return true if caller has permission to set the ktracing state
 1178  * of target.  Essentially, the target can't possess any
 1179  * more permissions than the caller.  KTRFAC_ROOT signifies that
 1180  * root previously set the tracing status on the target process, and
 1181  * so, only root may further change it.
 1182  *
 1183  * TODO: check groups.  use caller effective gid.
 1184  */
 1185 int
 1186 ktrcanset(struct proc *callp, struct proc *targetp)
 1187 {
 1188         struct pcred *caller = callp->p_cred;
 1189         struct pcred *target = targetp->p_cred;
 1190 
 1191         if ((caller->pc_ucred->cr_uid == target->p_ruid &&
 1192             target->p_ruid == target->p_svuid &&
 1193             caller->p_rgid == target->p_rgid && /* XXX */
 1194             target->p_rgid == target->p_svgid &&
 1195             (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
 1196             (targetp->p_flag & P_SUGID) == 0) ||
 1197             caller->pc_ucred->cr_uid == 0)
 1198                 return (1);
 1199 
 1200         return (0);
 1201 }
 1202 #endif /* KTRACE */
 1203 
 1204 /*
 1205  * Put user defined entry to ktrace records.
 1206  */
 1207 int
 1208 sys_utrace(struct lwp *l, void *v, register_t *retval)
 1209 {
 1210 #ifdef KTRACE
 1211         struct sys_utrace_args /* {
 1212                 syscallarg(const char *) label;
 1213                 syscallarg(void *) addr;
 1214                 syscallarg(size_t) len;
 1215         } */ *uap = v;
 1216         struct proc *p = l->l_proc;
 1217 
 1218         if (!KTRPOINT(p, KTR_USER))
 1219                 return (0);
 1220         
 1221         return ktruser(p, SCARG(uap, label), SCARG(uap, addr),
 1222                 SCARG(uap, len), 1);
 1223 
 1224 #else /* !KTRACE */
 1225         return ENOSYS;
 1226 #endif /* KTRACE */
 1227 }

Cache object: 8af8ae25703651eac35b24e94afca14b


[ 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.