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/ddb/db_examine.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_examine.c,v $
   29  * Revision 2.14  93/11/17  16:21:44  dbg
   30  *      ANSI-fied.  Removed db_strcpy in favor of string package
   31  *      (kern/strings.h).
   32  *      [93/10/11            dbg]
   33  * 
   34  * Revision 2.13  93/05/17  10:26:31  rvb
   35  *      Type casts, etc to quiet gcc 2.3.3 warnings
   36  * 
   37  * Revision 2.12  93/03/09  17:55:55  danner
   38  *      Added ',' format to examine command.
   39  *      [93/02/25            jfriedl]
   40  * 
   41  * Revision 2.11  93/01/14  17:24:52  danner
   42  *      64bit cleanup.
   43  *      [92/12/10  16:16:01  af]
   44  * 
   45  * Revision 2.10  92/08/03  17:30:58  jfriedl
   46  *      removed silly prototypes
   47  *      [92/08/02            jfriedl]
   48  * 
   49  * Revision 2.9  92/05/21  17:06:44  jfriedl
   50  *      Added void type to functions that needed it.
   51  *      Added init to 'size' in db_search_cmd(). Removed unused variables.
   52  *      Other cleanup to quiet gcc warnings.
   53  *      [92/05/16            jfriedl]
   54  * 
   55  * Revision 2.8  92/05/04  11:23:59  danner
   56  *      x/u now examines current user space. x/t still examines user
   57  *      space of the the specified thread. x/tu is redundant. 
   58  *      To examine an value as unsigned decimal, use x/U. 
   59  *      [92/04/18            danner]
   60  * 
   61  * Revision 2.7  91/10/09  15:59:28  af
   62  *      Supported non current task space data examination and search.
   63  *      Added 'm' format and db_xcdump to print with hex and characters.
   64  *      Added db_examine_{forward, backward}.
   65  *      Changed db_print_cmd to support variable number of parameters
   66  *      including string constant.
   67  *      Included "db_access.h".
   68  *      [91/08/29            tak]
   69  * 
   70  * Revision 2.6  91/08/28  11:11:01  jsb
   71  *      Added 'A' flag to examine: just like 'a' (address), but prints addr
   72  *      as a procedure type, thus printing file/line info if available.
   73  *      Useful when called as 'x/Ai'.
   74  *      [91/08/13  18:14:55  jsb]
   75  * 
   76  * Revision 2.5  91/05/14  15:33:31  mrt
   77  *      Correcting copyright
   78  * 
   79  * Revision 2.4  91/02/05  17:06:20  mrt
   80  *      Changed to new Mach copyright
   81  *      [91/01/31  16:17:37  mrt]
   82  * 
   83  * Revision 2.3  90/11/07  16:49:23  rpd
   84  *      Added db_search_cmd, db_search.
   85  *      [90/11/06            rpd]
   86  * 
   87  * Revision 2.2  90/08/27  21:50:38  dbg
   88  *      Add 'r', 'z' to print and examine formats.
   89  *      Change calling sequence of db_disasm.
   90  *      db_examine sets db_prev and db_next instead of explicitly
   91  *      advancing dot.
   92  *      [90/08/20            dbg]
   93  *      Reflected changes in db_printsym()'s calling seq.
   94  *      [90/08/20            af]
   95  *      Reduce lint.
   96  *      [90/08/07            dbg]
   97  *      Created.
   98  *      [90/07/25            dbg]
   99  * 
  100  */
  101 /*
  102  *      Author: David B. Golub, Carnegie Mellon University
  103  *      Date:   7/90
  104  */
  105 #include <mach/boolean.h>
  106 #include <machine/db_machdep.h>
  107 
  108 #include <kern/strings.h>
  109 
  110 #include <ddb/db_access.h>
  111 #include <ddb/db_lex.h>
  112 #include <ddb/db_output.h>
  113 #include <ddb/db_command.h>
  114 #include <ddb/db_sym.h>
  115 #include <ddb/db_task_thread.h>
  116 #include <ddb/db_examine.h>
  117 
  118 #include <kern/thread.h>
  119 #include <kern/task.h>
  120 
  121 #include <mach/vm_param.h>
  122 
  123 #define db_thread_to_task(thread)       ((thread)? thread->task: TASK_NULL)
  124 
  125 char            db_examine_format[TOK_STRING_SIZE] = "x";
  126 int             db_examine_count = 1;
  127 db_addr_t       db_examine_prev_addr = 0;
  128 thread_t        db_examine_thread = THREAD_NULL;
  129 
  130 extern  db_addr_t db_disasm(db_addr_t pc, boolean_t altform, task_t task);
  131                         /* instruction disassembler */
  132 
  133 #define DB_XCDUMP_NC    16
  134 
  135 db_addr_t
  136 db_xcdump(
  137         db_addr_t       addr,
  138         int             size,
  139         int             count,
  140         task_t          task)
  141 {
  142         register        i, n;
  143         db_expr_t       value;
  144         int             bcount;
  145         db_addr_t       off;
  146         char            *name;
  147         char            data[DB_XCDUMP_NC];
  148 
  149         db_find_task_sym_and_offset(addr, &name, &off, task);
  150         for (n = count*size; n > 0; n -= bcount) {
  151             db_prev = addr;
  152             if (off == 0) {
  153                 db_printf("%s:\n", name);
  154                 off = -1;
  155             }
  156             db_printf("%0*X:%s", 2*sizeof(db_addr_t), addr,
  157                         (size != 1)? " ": "");
  158             bcount = ((n > DB_XCDUMP_NC)? DB_XCDUMP_NC: n);
  159             if (trunc_page(addr) != trunc_page(addr+bcount-1)) {
  160                 db_addr_t next_page_addr = trunc_page(addr+bcount-1);
  161                 if (!DB_CHECK_ACCESS(next_page_addr, sizeof(int), task))
  162                     bcount = next_page_addr - addr;
  163             }
  164             db_read_bytes(addr, bcount, data, task);
  165             for (i = 0; i < bcount && off != 0; i += size) {
  166                 if (i % 4 == 0)
  167                         db_printf(" ");
  168                 value = db_get_task_value(addr, size, FALSE, task);
  169                 db_printf("%0*x ", size*2, value);
  170                 addr += size;
  171                 db_find_task_sym_and_offset(addr, &name, &off, task);
  172             }
  173             db_printf("%*s",
  174                         ((DB_XCDUMP_NC-i)/size)*(size*2+1)+(DB_XCDUMP_NC-i)/4,
  175                          "");
  176             bcount = i;
  177             db_printf("%s*", (size != 1)? " ": "");
  178             for (i = 0; i < bcount; i++) {
  179                 value = data[i];
  180                 db_printf("%c", (value >= ' ' && value <= '~')? value: '.');
  181             }
  182             db_printf("*\n");
  183         }
  184         return addr;
  185 }
  186 
  187 void
  188 db_examine(
  189         register
  190         db_addr_t       addr,
  191         char *          fmt,    /* format string */
  192         int             count,  /* repeat count */
  193         task_t          task)
  194 {
  195         int             c;
  196         db_expr_t       value;
  197         int             size;   /* in bytes */
  198         int             width;
  199         char *          fp;
  200 
  201         db_examine_prev_addr = addr;
  202         while (--count >= 0) {
  203             fp = fmt;
  204             size = sizeof(int);
  205             width = 4*size;
  206             while ((c = *fp++) != 0) {
  207                 switch (c) {
  208                     case 'b':
  209                         size = sizeof(char);
  210                         width = 4*size;
  211                         break;
  212                     case 'h':
  213                         size = sizeof(short);
  214                         width = 4*size;
  215                         break;
  216                     case 'l':
  217                         size = sizeof(long);
  218                         width = 4*size;
  219                         break;
  220                     case 'a':   /* address */
  221                     case 'A':   /* function address */
  222                         /* always forces a new line */
  223                         if (db_print_position() != 0)
  224                             db_printf("\n");
  225                         db_prev = addr;
  226                         db_task_printsym(addr, 
  227                                         (c == 'a')?DB_STGY_ANY:DB_STGY_PROC,
  228                                         task);
  229                         db_printf(":\t");
  230                         break;
  231                     case 'm':
  232                         db_next = db_xcdump(addr, size, count+1, task);
  233                         return;
  234                     default:
  235                         if (db_print_position() == 0) {
  236                             /* If we hit a new symbol, print it */
  237                             char *      name;
  238                             db_addr_t   off;
  239 
  240                             db_find_task_sym_and_offset(addr,&name,&off,task);
  241                             if (off == 0)
  242                                 db_printf("%s:\t", name);
  243                             else
  244                                 db_printf("\t\t");
  245 
  246                             db_prev = addr;
  247                         }
  248 
  249                         switch (c) {
  250                             case ',':   /* skip one unit w/o printing */
  251                                 addr += size;
  252                                 break;
  253 
  254                             case 'r':   /* signed, current radix */
  255                                 value = db_get_task_value(addr,size,TRUE,task);
  256                                 addr += size;
  257                                 db_printf("%-*R", width, value);
  258                                 break;
  259                             case 'x':   /* unsigned hex */
  260                                 value = db_get_task_value(addr,size,FALSE,task);
  261                                 addr += size;
  262                                 db_printf("%-*X", width, value);
  263                                 break;
  264                             case 'z':   /* signed hex */
  265                                 value = db_get_task_value(addr,size,TRUE,task);
  266                                 addr += size;
  267                                 db_printf("%-*Z", width, value);
  268                                 break;
  269                             case 'd':   /* signed decimal */
  270                                 value = db_get_task_value(addr,size,TRUE,task);
  271                                 addr += size;
  272                                 db_printf("%-*D", width, value);
  273                                 break;
  274                             case 'U':   /* unsigned decimal */
  275                                 value = db_get_task_value(addr,size,FALSE,task);
  276                                 addr += size;
  277                                 db_printf("%-*U", width, value);
  278                                 break;
  279                             case 'o':   /* unsigned octal */
  280                                 value = db_get_task_value(addr,size,FALSE,task);
  281                                 addr += size;
  282                                 db_printf("%-*O", width, value);
  283                                 break;
  284                             case 'c':   /* character */
  285                                 value = db_get_task_value(addr,1,FALSE,task);
  286                                 addr += 1;
  287                                 if (value >= ' ' && value <= '~')
  288                                     db_printf("%c", value);
  289                                 else
  290                                     db_printf("\\%03o", value);
  291                                 break;
  292                             case 's':   /* null-terminated string */
  293                                 for (;;) {
  294                                     value = db_get_task_value(addr,1,FALSE,task);
  295                                     addr += 1;
  296                                     if (value == 0)
  297                                         break;
  298                                     if (value >= ' ' && value <= '~')
  299                                         db_printf("%c", value);
  300                                     else
  301                                         db_printf("\\%03o", value);
  302                                 }
  303                                 break;
  304                             case 'i':   /* instruction */
  305                                 addr = db_disasm(addr, FALSE, task);
  306                                 break;
  307                             case 'I':   /* instruction, alternate form */
  308                                 addr = db_disasm(addr, TRUE, task);
  309                                 break;
  310                             default:
  311                                 break;
  312                         }
  313                         if (db_print_position() != 0)
  314                             db_end_line();
  315                         break;
  316                 }
  317             }
  318         }
  319         db_next = addr;
  320 }
  321 
  322 /*
  323  * Examine (print) data.
  324  */
  325 /*ARGSUSED*/
  326 void
  327 db_examine_cmd(
  328         db_expr_t       addr,
  329         int             have_addr,
  330         db_expr_t       count,
  331         char *          modif)
  332 {
  333         thread_t        thread;
  334 
  335         if (modif[0] != '\0')
  336             strcpy(db_examine_format, modif);
  337 
  338         if (count == -1)
  339             count = 1;
  340         db_examine_count = count;
  341         if (db_option(modif, 't')) 
  342           {
  343             if (!db_get_next_thread(&thread, 0))
  344               return;
  345           }
  346         else 
  347           if (db_option(modif,'u'))
  348             thread = current_thread();
  349           else
  350             thread = THREAD_NULL;
  351         
  352         db_examine_thread = thread;
  353         db_examine((db_addr_t) addr, db_examine_format, count, 
  354                                         db_thread_to_task(thread));
  355 }
  356 
  357 /* ARGSUSED */
  358 void
  359 db_examine_forward(
  360         db_expr_t       addr,
  361         int             have_addr,
  362         db_expr_t       count,
  363         char *          modif)
  364 {
  365         db_examine(db_next, db_examine_format, db_examine_count,
  366                                 db_thread_to_task(db_examine_thread));
  367 }
  368 
  369 /* ARGSUSED */
  370 void
  371 db_examine_backward(
  372         db_expr_t       addr,
  373         int             have_addr,
  374         db_expr_t       count,
  375         char *          modif)
  376 {
  377 
  378         db_examine(db_examine_prev_addr - (db_next - db_examine_prev_addr),
  379                          db_examine_format, db_examine_count,
  380                                 db_thread_to_task(db_examine_thread));
  381 }
  382 
  383 /*
  384  * Print value.
  385  */
  386 char    db_print_format = 'x';
  387 
  388 /*ARGSUSED*/
  389 void
  390 db_print_cmd()
  391 {
  392         db_expr_t       value;
  393         int             t;
  394         task_t          task = TASK_NULL;
  395 
  396         if ((t = db_read_token()) == tSLASH) {
  397             if (db_read_token() != tIDENT) {
  398                 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
  399                 db_error(0);
  400                 /* NOTREACHED */
  401             }
  402             if (db_tok_string[0])
  403                 db_print_format = db_tok_string[0];
  404             if (db_option(db_tok_string, 't') && db_default_thread)
  405                 task = db_default_thread->task;
  406         } else
  407             db_unread_token(t);
  408         
  409         for ( ; ; ) {
  410             t = db_read_token();
  411             if (t == tSTRING) {
  412                 db_printf("%s", db_tok_string);
  413                 continue;
  414             }
  415             db_unread_token(t);
  416             if (!db_expression(&value))
  417                 break;
  418             switch (db_print_format) {
  419             case 'a':
  420                 db_task_printsym((db_addr_t)value, DB_STGY_ANY, task);
  421                 break;
  422             case 'r':
  423                 db_printf("%*r", 3+2*sizeof(db_expr_t), value);
  424                 break;
  425             case 'x':
  426                 db_printf("%*x", 2*sizeof(db_expr_t), value);
  427                 break;
  428             case 'z':
  429                 db_printf("%*z", 2*sizeof(db_expr_t), value);
  430                 break;
  431             case 'd':
  432                 db_printf("%*d", 3+2*sizeof(db_expr_t), value);
  433                 break;
  434             case 'u':
  435                 db_printf("%*u", 3+2*sizeof(db_expr_t), value);
  436                 break;
  437             case 'o':
  438                 db_printf("%o", 4*sizeof(db_expr_t), value);
  439                 break;
  440             case 'c':
  441                 value = value & 0xFF;
  442                 if (value >= ' ' && value <= '~')
  443                     db_printf("%c", value);
  444                 else
  445                     db_printf("\\%03o", value);
  446                 break;
  447             default:
  448                 db_printf("Unknown format %c\n", db_print_format);
  449                 db_print_format = 'x';
  450                 db_error(0);
  451             }
  452         }
  453 }
  454 
  455 void
  456 db_print_loc_and_inst(
  457         db_addr_t       loc,
  458         task_t          task)
  459 {
  460         db_task_printsym(loc, DB_STGY_PROC, task);
  461         db_printf(":\t");
  462         (void) db_disasm(loc, TRUE, task);
  463 }
  464 
  465 void
  466 db_search(
  467         register
  468         db_addr_t       addr,
  469         int             size,
  470         db_expr_t       value,
  471         db_expr_t       mask,
  472         unsigned int    count,
  473         task_t          task)
  474 {
  475         while (count-- != 0) {
  476                 db_prev = addr;
  477                 if ((db_get_task_value(addr,size,FALSE,task) & mask) == value)
  478                         break;
  479                 addr += size;
  480         }
  481         db_next = addr;
  482 }
  483 
  484 /*
  485  * Search for a value in memory.
  486  * Syntax: search [/bhl] addr value [mask] [,count] [thread]
  487  */
  488 void
  489 db_search_cmd()
  490 {
  491         int             t;
  492         db_addr_t       addr;
  493         int             size = 0;
  494         db_expr_t       value;
  495         db_expr_t       mask;
  496         db_addr_t       count;
  497         thread_t        thread;
  498         boolean_t       thread_flag = FALSE;
  499         register char   *p;
  500 
  501         t = db_read_token();
  502         if (t == tSLASH) {
  503             t = db_read_token();
  504             if (t != tIDENT) {
  505               bad_modifier:
  506                 db_printf("Bad modifier \"/%s\"\n", db_tok_string);
  507                 db_flush_lex();
  508                 return;
  509             }
  510 
  511             for (p = db_tok_string; *p; p++) {
  512                 switch(*p) {
  513                 case 'b':
  514                     size = sizeof(char);
  515                     break;
  516                 case 'h':
  517                     size = sizeof(short);
  518                     break;
  519                 case 'l':
  520                     size = sizeof(long);
  521                     break;
  522                 case 't':
  523                     thread_flag = TRUE;
  524                     break;
  525                 default:
  526                     goto bad_modifier;
  527                 }
  528             }
  529         } else {
  530             db_unread_token(t);
  531             size = sizeof(int);
  532         }
  533 
  534         if (!db_expression(&addr)) {
  535             db_printf("Address missing\n");
  536             db_flush_lex();
  537             return;
  538         }
  539 
  540         if (!db_expression(&value)) {
  541             db_printf("Value missing\n");
  542             db_flush_lex();
  543             return;
  544         }
  545 
  546         if (!db_expression(&mask))
  547             mask = ~0;
  548 
  549         t = db_read_token();
  550         if (t == tCOMMA) {
  551             if (!db_expression(&count)) {
  552                 db_printf("Count missing\n");
  553                 db_flush_lex();
  554                 return;
  555             }
  556         } else {
  557             db_unread_token(t);
  558             count = -1;         /* effectively forever */
  559         }
  560         if (thread_flag) {
  561             if (!db_get_next_thread(&thread, 0))
  562                 return;
  563         } else
  564             thread = THREAD_NULL;
  565 
  566         db_search(addr, size, value, mask, count, db_thread_to_task(thread));
  567 }
  568 

Cache object: c2edc8ccca150d4f1a9e4411db234926


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