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

Cache object: f0394ba3aa0519e0ee9ae025ed9f50de


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