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/i386/db_interface.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  * Mach Operating System
    3  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        db_interface.c,v $
   29  * Revision 2.13  93/11/17  16:35:19  dbg
   30  *      ANSI-fied.
   31  *      [93/11/03            dbg]
   32  * 
   33  *      Added option of faulting in pages in db_user_to_kernel_address(),
   34  *      controlled by the global variable db_no_vm_fault, same as mips/alpha.
   35  *      [93/09/25            af]
   36  * 
   37  * Revision 2.12  93/05/15  19:13:52  mrt
   38  *      machparam.h -> machspl.h
   39  * 
   40  * Revision 2.11  93/01/14  17:28:37  danner
   41  *      Pick up multiprocessor DDB changes from Grenoble.
   42  *      [92/10/23            dbg]
   43  * 
   44  * Revision 2.10  92/02/19  16:29:17  elf
   45  *      MD debugger support.
   46  *      [92/02/07            rvb]
   47  * 
   48  * Revision 2.9  92/01/03  20:05:13  dbg
   49  *      Always enter debugger - ignore RB_KDB.
   50  *      [91/10/30            dbg]
   51  * 
   52  * Revision 2.8  91/10/09  16:06:14  af
   53  *      Added user space access and check routines.
   54  *      Added U*X task information print routines.
   55  *      Changed db_trap to db_task_trap.
   56  *      [91/08/29            tak]
   57  * 
   58  * Revision 2.7  91/07/31  17:35:23  dbg
   59  *      Registers are in different locations on keyboard interrupt.
   60  *      [91/07/30  16:48:52  dbg]
   61  * 
   62  * Revision 2.6  91/05/14  16:05:37  mrt
   63  *      Correcting copyright
   64  * 
   65  * Revision 2.5  91/03/16  14:44:00  rpd
   66  *      Fixed kdb_trap to skip over permanent breakpoints.
   67  *      [91/03/15            rpd]
   68  * 
   69  *      Changed kdb_trap to use db_recover.
   70  *      [91/01/14            rpd]
   71  * 
   72  *      Fixed kdb_trap to disable interrupts.
   73  *      [91/01/12            rpd]
   74  * 
   75  * Revision 2.4  91/02/05  17:11:13  mrt
   76  *      Changed to new Mach copyright
   77  *      [91/02/01  17:31:17  mrt]
   78  * 
   79  * Revision 2.3  90/12/04  14:45:55  jsb
   80  *      Changes for merged intel/pmap.{c,h}.
   81  *      [90/12/04  11:14:41  jsb]
   82  * 
   83  * Revision 2.2  90/10/25  14:44:43  rwd
   84  *      Added watchpoint support.
   85  *      [90/10/18            rpd]
   86  * 
   87  *      Created.
   88  *      [90/07/25            dbg]
   89  * 
   90  */
   91 
   92 /*
   93  * Interface to new debugger.
   94  */
   95 
   96 #include <cpus.h>
   97 
   98 #include <sys/reboot.h>
   99 
  100 #include <mach/vm_param.h>
  101 
  102 #include <kern/cpu_number.h>
  103 #include <kern/kern_io.h>
  104 #include <kern/task.h>
  105 #include <kern/thread.h>
  106 
  107 #include <vm/pmap.h>
  108 #include <vm/vm_fault.h>
  109 #include <vm/vm_map.h>
  110 
  111 #include <ddb/db_access.h>
  112 #include <ddb/db_command.h>             /* db_error */
  113 #include <ddb/db_output.h>
  114 #include <ddb/db_task_thread.h>
  115 
  116 #include <i386/db_machdep.h>
  117 #include <i386/machspl.h>
  118 #include <i386/pmap.h>
  119 #include <i386/seg.h>
  120 #include <i386/setjmp.h>
  121 #include <i386/thread.h>
  122 #include <i386/trap.h>
  123 
  124 
  125 struct   i386_saved_state *i386_last_saved_statep;
  126 struct   i386_saved_state i386_nested_saved_state;
  127 unsigned i386_last_kdb_sp;
  128 
  129 extern  thread_t db_default_thread;
  130 
  131 extern char *   trap_type[];
  132 extern int      TRAP_TYPES;
  133 
  134 /*
  135  * Print trap reason.
  136  */
  137 void kdbprinttrap(
  138         int     type,
  139         int     code)
  140 {
  141         db_printf("kernel: ");
  142         if (type > TRAP_TYPES)
  143             db_printf("type %d", type);
  144         else
  145             db_printf("%s", trap_type[type]);
  146         db_printf(" trap, code=%x\n", code);
  147 }
  148 
  149 /*
  150  *  kdb_trap - field a TRACE or BPT trap
  151  */
  152 
  153 extern jmp_buf_t *db_recover;
  154 spl_t saved_ipl[NCPUS]; /* just to know what was IPL before trap */
  155 
  156 boolean_t
  157 kdb_trap(
  158         int     type,
  159         int     code,
  160         register struct i386_saved_state *regs)
  161 {
  162         spl_t   s;
  163 
  164         s = splhigh();
  165         saved_ipl[cpu_number()] = s;
  166 
  167         switch (type) {
  168             case T_DEBUG:       /* single_step */
  169             {
  170                 extern int dr_addr[];
  171                 int addr;
  172                 int status = dr6();
  173 
  174                 if (status & 0xf) {     /* hmm hdw break */
  175                         addr =  status & 0x8 ? dr_addr[3] :
  176                                 status & 0x4 ? dr_addr[2] :
  177                                 status & 0x2 ? dr_addr[1] :
  178                                                dr_addr[0];
  179                         regs->efl |= EFL_RF;
  180                         db_single_step_cmd(addr, 0, 1, "p");
  181                 }
  182             }
  183             case T_INT3:        /* breakpoint */
  184             case T_WATCHPOINT:  /* watchpoint */
  185             case -1:    /* keyboard interrupt */
  186                 break;
  187 
  188             default:
  189                 if (db_recover) {
  190                     i386_nested_saved_state = *regs;
  191                     db_printf("Caught ");
  192                     if (type > TRAP_TYPES)
  193                         db_printf("type %d", type);
  194                     else
  195                         db_printf("%s", trap_type[type]);
  196                     db_printf(" trap, code = %x, pc = %x\n",
  197                               code, regs->eip);
  198                     db_error("");
  199                     /*NOTREACHED*/
  200                 }
  201                 kdbprinttrap(type, code);
  202         }
  203 
  204 #if     NCPUS > 1
  205         if (db_enter())
  206 #endif  /* NCPUS > 1 */
  207         {
  208             i386_last_saved_statep = regs;
  209             i386_last_kdb_sp = (unsigned) &type;
  210 
  211             /* XXX Should switch to ddb`s own stack here. */
  212 
  213             ddb_regs = *regs;
  214             if ((regs->cs & 0x3) == 0) {
  215                 /*
  216                  * Kernel mode - esp and ss not saved
  217                  */
  218                 ddb_regs.uesp = (int)&regs->uesp;   /* kernel stack pointer */
  219                 ddb_regs.ss   = KERNEL_DS;
  220             }
  221 
  222             cnpollc(TRUE);
  223             db_task_trap(type, code, (regs->cs & 0x3) != 0);
  224             cnpollc(FALSE);
  225 
  226             regs->eip    = ddb_regs.eip;
  227             regs->efl    = ddb_regs.efl;
  228             regs->eax    = ddb_regs.eax;
  229             regs->ecx    = ddb_regs.ecx;
  230             regs->edx    = ddb_regs.edx;
  231             regs->ebx    = ddb_regs.ebx;
  232             if (regs->cs & 0x3) {
  233                 /*
  234                  * user mode - saved esp and ss valid
  235                  */
  236                 regs->uesp = ddb_regs.uesp;             /* user stack pointer */
  237                 regs->ss   = ddb_regs.ss & 0xffff;      /* user stack segment */
  238             }
  239             regs->ebp    = ddb_regs.ebp;
  240             regs->esi    = ddb_regs.esi;
  241             regs->edi    = ddb_regs.edi;
  242             regs->es     = ddb_regs.es & 0xffff;
  243             regs->cs     = ddb_regs.cs & 0xffff;
  244             regs->ds     = ddb_regs.ds & 0xffff;
  245             regs->fs     = ddb_regs.fs & 0xffff;
  246             regs->gs     = ddb_regs.gs & 0xffff;
  247 
  248             if ((type == T_INT3) &&
  249                 (db_get_task_value(regs->eip, BKPT_SIZE, FALSE, TASK_NULL)
  250                                                                  == BKPT_INST))
  251                 regs->eip += BKPT_SIZE;
  252         }
  253 #if     NCPUS > 1
  254         db_leave();
  255 #endif  /* NCPUS > 1 */
  256 
  257         splx(s);
  258         return 1;
  259 }
  260 
  261 /*
  262  *      Enter KDB through a keyboard trap.
  263  *      We show the registers as of the keyboard interrupt
  264  *      instead of those at its call to KDB.
  265  */
  266 struct int_regs {
  267         int     gs;
  268         int     fs;
  269         int     edi;
  270         int     esi;
  271         int     ebp;
  272         int     ebx;
  273         struct i386_interrupt_state *is;
  274 };
  275 
  276 void
  277 kdb_kentry(
  278         struct int_regs *int_regs)
  279 {
  280         struct i386_interrupt_state *is = int_regs->is;
  281         spl_t   s = splhigh();
  282 
  283 #if     NCPUS > 1
  284         if (db_enter())
  285 #endif  /* NCPUS > 1 */
  286         {
  287             if (is->cs & 0x3) {
  288                 ddb_regs.uesp = ((int *)(is+1))[0];
  289                 ddb_regs.ss   = ((int *)(is+1))[1];
  290             }
  291             else {
  292                 ddb_regs.ss  = KERNEL_DS;
  293                 ddb_regs.uesp= (int)(is+1);
  294             }
  295             ddb_regs.efl = is->efl;
  296             ddb_regs.cs  = is->cs;
  297             ddb_regs.eip = is->eip;
  298             ddb_regs.eax = is->eax;
  299             ddb_regs.ecx = is->ecx;
  300             ddb_regs.edx = is->edx;
  301             ddb_regs.ebx = int_regs->ebx;
  302             ddb_regs.ebp = int_regs->ebp;
  303             ddb_regs.esi = int_regs->esi;
  304             ddb_regs.edi = int_regs->edi;
  305             ddb_regs.ds  = is->ds;
  306             ddb_regs.es  = is->es;
  307             ddb_regs.fs  = int_regs->fs;
  308             ddb_regs.gs  = int_regs->gs;
  309 
  310             cnpollc(TRUE);
  311             db_task_trap(-1, 0, (ddb_regs.cs & 0x3) != 0);
  312             cnpollc(FALSE);
  313 
  314             if (ddb_regs.cs & 0x3) {
  315                 ((int *)(is+1))[0] = ddb_regs.uesp;
  316                 ((int *)(is+1))[1] = ddb_regs.ss & 0xffff;
  317             }
  318             is->efl = ddb_regs.efl;
  319             is->cs  = ddb_regs.cs & 0xffff;
  320             is->eip = ddb_regs.eip;
  321             is->eax = ddb_regs.eax;
  322             is->ecx = ddb_regs.ecx;
  323             is->edx = ddb_regs.edx;
  324             int_regs->ebx = ddb_regs.ebx;
  325             int_regs->ebp = ddb_regs.ebp;
  326             int_regs->esi = ddb_regs.esi;
  327             int_regs->edi = ddb_regs.edi;
  328             is->ds  = ddb_regs.ds & 0xffff;
  329             is->es  = ddb_regs.es & 0xffff;
  330             int_regs->fs = ddb_regs.fs & 0xffff;
  331             int_regs->gs = ddb_regs.gs & 0xffff;
  332         }
  333 #if     NCPUS > 1
  334         db_leave();
  335 #endif  /* NCPUS > 1 */
  336 
  337         splx(s);
  338 }
  339 
  340 boolean_t db_no_vm_fault = TRUE;
  341 
  342 int
  343 db_user_to_kernel_address(
  344         task_t          task,
  345         vm_offset_t     addr,
  346         unsigned        *kaddr,
  347         int             flag)
  348 {
  349         register pt_entry_t *ptp;
  350         boolean_t       faulted = FALSE;
  351         
  352 retry:
  353         ptp = pmap_pte(task->map->pmap, addr);
  354         if (ptp == PT_ENTRY_NULL || (*ptp & INTEL_PTE_VALID) == 0) {
  355             if (!faulted && !db_no_vm_fault) {
  356                 kern_return_t   err;
  357 
  358                 faulted = TRUE;
  359                 err = vm_fault( task->map,
  360                                 trunc_page(addr),
  361                                 VM_PROT_READ,
  362                                 FALSE, FALSE, 0);
  363                 if (err == KERN_SUCCESS)
  364                     goto retry;
  365             }
  366             if (flag) {
  367                 db_printf("\nno memory is assigned to address %08x\n", addr);
  368                 db_error(0);
  369                 /* NOTREACHED */
  370             }
  371             return -1;
  372         }
  373         *kaddr = (unsigned)ptetokv(*ptp) + (addr & (INTEL_PGBYTES-1));
  374         return 0;
  375 }
  376         
  377 /*
  378  * Read bytes from kernel address space for debugger.
  379  */
  380 
  381 void
  382 db_read_bytes(
  383         vm_offset_t     addr,
  384         register int    size,
  385         register char   *data,
  386         task_t          task)
  387 {
  388         register char   *src;
  389         register int    n;
  390         unsigned        kern_addr;
  391 
  392         src = (char *)addr;
  393         if (addr >= VM_MIN_KERNEL_ADDRESS || task == TASK_NULL) {
  394             if (task == TASK_NULL)
  395                 task = db_current_task();
  396             while (--size >= 0) {
  397                 if (addr++ < VM_MIN_KERNEL_ADDRESS && task == TASK_NULL) {
  398                     db_printf("\nbad address %x\n", addr);
  399                     db_error(0);
  400                     /* NOTREACHED */
  401                 }
  402                 *data++ = *src++;
  403             }
  404             return;
  405         }
  406         while (size > 0) {
  407             if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
  408                 return;
  409             src = (char *)kern_addr;
  410             n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
  411             if (n > size)
  412                 n = size;
  413             size -= n;
  414             addr += n;
  415             while (--n >= 0)
  416                 *data++ = *src++;
  417         }
  418 }
  419 
  420 /*
  421  * Write bytes to kernel address space for debugger.
  422  */
  423 void
  424 db_write_bytes(
  425         vm_offset_t     addr,
  426         register int    size,
  427         register char   *data,
  428         task_t          task)
  429 {
  430         register char   *dst;
  431 
  432         register pt_entry_t *ptep0 = 0;
  433         pt_entry_t      oldmap0 = 0;
  434         vm_offset_t     addr1;
  435         register pt_entry_t *ptep1 = 0;
  436         pt_entry_t      oldmap1 = 0;
  437         extern char     etext;
  438         void            db_write_bytes_user_space();
  439 
  440         if ((addr < VM_MIN_KERNEL_ADDRESS) ^ 
  441             ((addr + size) <= VM_MIN_KERNEL_ADDRESS)) {
  442             db_error("\ncannot write data into mixed space\n");
  443             /* NOTREACHED */
  444         }
  445         if (addr < VM_MIN_KERNEL_ADDRESS) {
  446             if (task) {
  447                 db_write_bytes_user_space(addr, size, data, task);
  448                 return;
  449             } else if (db_current_task() == TASK_NULL) {
  450                 db_printf("\nbad address %x\n", addr);
  451                 db_error(0);
  452                 /* NOTREACHED */
  453             }
  454         }
  455             
  456         if (addr >= VM_MIN_KERNEL_ADDRESS &&
  457             addr <= (vm_offset_t)&etext)
  458         {
  459             ptep0 = pmap_pte(kernel_pmap, addr);
  460             oldmap0 = *ptep0;
  461             *ptep0 |= INTEL_PTE_WRITE;
  462 
  463             addr1 = i386_trunc_page(addr + size - 1);
  464             if (i386_trunc_page(addr) != addr1) {
  465                 /* data crosses a page boundary */
  466 
  467                 ptep1 = pmap_pte(kernel_pmap, addr1);
  468                 oldmap1 = *ptep1;
  469                 *ptep1 |= INTEL_PTE_WRITE;
  470             }
  471             flush_tlb();
  472         }
  473 
  474         dst = (char *)addr;
  475 
  476         while (--size >= 0)
  477             *dst++ = *data++;
  478 
  479         if (ptep0) {
  480             *ptep0 = oldmap0;
  481             if (ptep1) {
  482                 *ptep1 = oldmap1;
  483             }
  484             flush_tlb();
  485         }
  486 }
  487         
  488 void
  489 db_write_bytes_user_space(
  490         vm_offset_t     addr,
  491         register int    size,
  492         register char   *data,
  493         task_t          task)
  494 {
  495         register char   *dst;
  496         register int    n;
  497         unsigned        kern_addr;
  498 
  499         while (size > 0) {
  500             if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0)
  501                 return;
  502             dst = (char *)kern_addr;
  503             n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
  504             if (n > size)
  505                 n = size;
  506             size -= n;
  507             addr += n;
  508             while (--n >= 0)
  509                 *dst++ = *data++;
  510         }
  511 }
  512 
  513 boolean_t
  514 db_check_access(
  515         vm_offset_t     addr,
  516         register int    size,
  517         task_t          task)
  518 {
  519         register        n;
  520         vm_offset_t     kern_addr;
  521 
  522         if (addr >= VM_MIN_KERNEL_ADDRESS) {
  523             if (kernel_task == TASK_NULL)
  524                 return TRUE;
  525             task = kernel_task;
  526         } else if (task == TASK_NULL) {
  527             if (current_thread() == THREAD_NULL)
  528                 return FALSE;
  529             task = current_thread()->task;
  530         }
  531         while (size > 0) {
  532             if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0)
  533                 return FALSE;
  534             n = intel_trunc_page(addr+INTEL_PGBYTES) - addr;
  535             if (n > size)
  536                 n = size;
  537             size -= n;
  538             addr += n;
  539         }
  540         return TRUE;
  541 }
  542 
  543 boolean_t
  544 db_phys_eq(
  545         task_t          task1,
  546         vm_offset_t     addr1,
  547         task_t          task2,
  548         vm_offset_t     addr2)
  549 {
  550         vm_offset_t     kern_addr1, kern_addr2;
  551 
  552         if (addr1 >= VM_MIN_KERNEL_ADDRESS || addr2 >= VM_MIN_KERNEL_ADDRESS)
  553             return FALSE;
  554         if ((addr1 & (INTEL_PGBYTES-1)) != (addr2 & (INTEL_PGBYTES-1)))
  555             return FALSE;
  556         if (task1 == TASK_NULL) {
  557             if (current_thread() == THREAD_NULL)
  558                 return FALSE;
  559             task1 = current_thread()->task;
  560         }
  561         if (db_user_to_kernel_address(task1, addr1, &kern_addr1, 0) < 0
  562                 || db_user_to_kernel_address(task2, addr2, &kern_addr2, 0) < 0)
  563             return FALSE;
  564         return(kern_addr1 == kern_addr2);
  565 }
  566 
  567 #define DB_USER_STACK_ADDR              (VM_MIN_KERNEL_ADDRESS)
  568 #define DB_NAME_SEARCH_LIMIT            (DB_USER_STACK_ADDR-(INTEL_PGBYTES*3))
  569 
  570 static boolean_t
  571 db_search_null(
  572         task_t          task,
  573         vm_offset_t     *svaddr,
  574         vm_offset_t     evaddr,
  575         vm_offset_t     *skaddr,
  576         int             flag)
  577 {
  578         register unsigned vaddr;
  579         register unsigned *kaddr;
  580 
  581         kaddr = (unsigned *)*skaddr;
  582         for (vaddr = *svaddr; vaddr > evaddr; vaddr -= sizeof(unsigned)) {
  583             if (vaddr % INTEL_PGBYTES == 0) {
  584                 vaddr -= sizeof(unsigned);
  585                 if (db_user_to_kernel_address(task, vaddr, skaddr, 0) < 0)
  586                     return FALSE;
  587                 kaddr = (vm_offset_t *)*skaddr;
  588             } else {
  589                 vaddr -= sizeof(unsigned);
  590                 kaddr--;
  591             }
  592             if ((*kaddr == 0) ^ (flag  == 0)) {
  593                 *svaddr = vaddr;
  594                 *skaddr = (unsigned)kaddr;
  595                 return TRUE;
  596             }
  597         }
  598         return FALSE;
  599 }
  600 
  601 void
  602 db_task_name(
  603         task_t          task)
  604 {
  605         register char *p;
  606         register n;
  607         unsigned vaddr, kaddr;
  608 
  609         vaddr = DB_USER_STACK_ADDR;
  610         kaddr = 0;
  611 
  612         /*
  613          * skip nulls at the end
  614          */
  615         if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 0)) {
  616             db_printf(DB_NULL_TASK_NAME);
  617             return;
  618         }
  619         /*
  620          * search start of args
  621          */
  622         if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 1)) {
  623             db_printf(DB_NULL_TASK_NAME);
  624             return;
  625         }
  626 
  627         n = DB_TASK_NAME_LEN-1;
  628         p = (char *)kaddr + sizeof(unsigned);
  629         for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR && n > 0; 
  630                                                         vaddr++, p++, n--) {
  631             if (vaddr % INTEL_PGBYTES == 0) {
  632                 (void)db_user_to_kernel_address(task, vaddr, &kaddr, 0);
  633                 p = (char*)kaddr;
  634             }
  635             db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p);
  636         }
  637         while (n-- >= 0)        /* compare with >= 0 for one more space */
  638             db_printf(" ");
  639 }

Cache object: 519aec7388fea19c0a0faa3622ec49d0


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