1 /*        $NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo Exp $  */
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  *
28  *        Author: David B. Golub, Carnegie Mellon University
29  *        Date:     7/90
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/buf.h>
38 #include <sys/proc.h>
39 
40 #include <ddb/ddb.h>
41 
42 static char         db_examine_format[TOK_STRING_SIZE] = "x";
43 
44 static void         db_examine(db_addr_t, char *, int);
45 static void         db_search(db_addr_t, int, db_expr_t, db_expr_t, unsigned int);
46 
47 /*
48  * Examine (print) data.  Syntax is:
49  *                  x/[bhl][cdiorsuxz]*
50  * For example, the command:
51  *        x/bxxxx
52  * should print:
53  *        address:  01  23  45  67
54  */
55 /*ARGSUSED*/
56 void
db_examine_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)57 db_examine_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
58     const char *modif)
59 {
60           if (modif[0] != '\0')
61                     strlcpy(db_examine_format, modif, sizeof(db_examine_format));
62 
63           if (count == -1)
64                     count = 1;
65 
66           db_examine((db_addr_t) addr, db_examine_format, count);
67 }
68 
69 static void
db_examine(db_addr_t addr,char * fmt,int count)70 db_examine(db_addr_t addr, char *fmt, int count)
71 {
72           int                 i, c;
73           quad_t              value;
74           int                 size;
75           int                 width;
76           int                 bytes;
77           char *              fp;
78           char                tbuf[24];
79 
80           while (--count >= 0) {
81                     fp = fmt;
82                     size = 4;
83                     width = 12;
84                     while ((c = *fp++) != 0) {
85                               if (db_print_position() == 0) {
86                                         /* Always print the address. */
87                                         db_printsym(addr, DB_STGY_ANY, db_printf);
88                                         db_printf(":\t");
89                                         db_prev = addr;
90                               }
91                               switch (c) {
92                               case 'b': /* byte */
93                                         size = 1;
94                                         width = 4;
95                                         break;
96                               case 'h': /* half-word */
97                                         size = 2;
98                                         width = 8;
99                                         break;
100                               case 'l': /* long-word */
101                                         size = 4;
102                                         width = 12;
103                                         break;
104                               case 'q': /* quad-word */
105                                         size = 8;
106                                         width = 24;
107                                         break;
108                               case 'L': /* implementation maximum */
109                                         size = sizeof value;
110                                         width = 12 * (sizeof value / 4);
111                                         break;
112                               case 'a': /* address */
113                                         db_printf("= 0x%lx\n", (long)addr);
114                                         break;
115                               case 'p':
116                                         size = sizeof(void *);
117                                         value = db_get_value(addr, size, false);
118                                         addr += size;
119                                         db_printf("= 0x%lx ", (long)value);
120                                         db_printsym((db_addr_t)value, DB_STGY_ANY, db_printf);
121                                         db_printf("\n");
122                                         break;
123                               case 'r': /* signed, current radix */
124                                         value = db_get_qvalue(addr, size, true);
125                                         addr += size;
126                                         db_format_radix(tbuf, 24, value, false);
127                                         db_printf("%-*s", width, tbuf);
128                                         break;
129                               case 'x': /* unsigned hex */
130                                         value = db_get_qvalue(addr, size, false);
131                                         addr += size;
132                                         db_printf("%-*" PRIx64, width, value);
133                                         break;
134                               case 'm': /* hex dump */
135                                         /*
136                                          * Print off in chunks of size. Try to print 16
137                                          * bytes at a time into 16/size columns. This
138                                          * loops modify's count extra times in order
139                                          * to get the nicely formatted lines.
140                                          */
141 
142                                         bytes = 0;
143                                         do {
144                                                   for (i = 0; i < size; i++) {
145                                                             value =
146 #if BYTE_ORDER == LITTLE_ENDIAN
147                                                                 db_get_value(addr +
148                                                                 (bytes & ~(size - 1)) +
149                                                                 size - i - 1, 1, false);
150 #else
151                                                                 db_get_value(addr + bytes,
152                                                                 1, false);
153 #endif
154                                                             db_printf(
155                                                                 "%02" PRIx64,
156                                                                 value);
157                                                             bytes++;
158                                                             if (!(bytes % size))
159                                                                       db_printf(" ");
160                                                   }
161                                         } while ((bytes != 16) && count--);
162                                         /* True up the columns before continuing */
163                                         for (i = 4; i >= (bytes / 4); i--)
164                                                   db_printf ("\t");
165                                         /* Print chars,  use . for non-printable's. */
166                                         while (bytes--) {
167                                                   value = db_get_value(addr, 1, false);
168                                                   addr += 1;
169                                                   if (value >= ' ' && value <= '~')
170                                                             db_printf("%c", (char)value);
171                                                   else
172                                                             db_printf(".");
173                                         }
174                                         db_printf("\n");
175                                         break;
176                               case 'z': /* signed hex */
177                                         value = db_get_qvalue(addr, size, true);
178                                         addr += size;
179                                         db_format_hex(tbuf, 24, value, false);
180                                         db_printf("%-*s", width, tbuf);
181                                         break;
182                               case 'd': /* signed decimal */
183                                         value = db_get_qvalue(addr, size, true);
184                                         addr += size;
185                                         db_printf("%-*" PRId64, width, value);
186                                         break;
187                               case 'u': /* unsigned decimal */
188                                         value = db_get_qvalue(addr, size, false);
189                                         addr += size;
190                                         db_printf("%-*" PRIu64, width, value);
191                                         break;
192                               case 'o': /* unsigned octal */
193                                         value = db_get_qvalue(addr, size, false);
194                                         addr += size;
195                                         db_printf("%-*" PRIo64, width, value);
196                                         break;
197                               case 'c': /* character */
198                                         value = db_get_value(addr, 1, false);
199                                         addr += 1;
200                                         if (value >= ' ' && value <= '~')
201                                                   db_printf("%c", (char)value);
202                                         else
203                                                   db_printf("\\%03o", (int)value);
204                                         break;
205                               case 's': /* null-terminated string */
206                                         for (;;) {
207                                                   value = db_get_value(addr, 1, false);
208                                                   addr += 1;
209                                                   if (value == 0)
210                                                             break;
211                                                   if (value >= ' ' && value <= '~')
212                                                             db_printf("%c", (char)value);
213                                                   else
214                                                             db_printf("\\%03o", (int)value);
215                                         }
216                                         break;
217                               case 'i': /* instruction */
218                                         addr = db_disasm(addr, false);
219                                         break;
220                               case 'I': /* instruction, alternate form */
221                                         addr = db_disasm(addr, true);
222                                         break;
223                               default:
224                                         break;
225                               }
226                               if (db_print_position() != 0)
227                                         db_end_line();
228                     }
229           }
230           db_next = addr;
231 }
232 
233 /*
234  * Print value.
235  */
236 static char         db_print_format = 'x';
237 
238 /*ARGSUSED*/
239 void
db_print_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)240 db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
241     const char *modif)
242 {
243           db_expr_t value;
244 
245           if (modif[0] != '\0')
246                     db_print_format = modif[0];
247 
248           switch (db_print_format) {
249           case 'a':
250                     db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
251                     break;
252           case 'r':
253                     {
254                               char tbuf[24];
255 
256                               db_format_radix(tbuf, 24, addr, false);
257                               db_printf("%11s", tbuf);
258                               break;
259                     }
260           case 'x':
261                     db_printf("%16" DDB_EXPR_FMT "x", addr);
262                     break;
263           case 'z':
264                     {
265                               char tbuf[24];
266 
267                               db_format_hex(tbuf, 24, addr, false);
268                               db_printf("%8s", tbuf);
269                               break;
270                     }
271           case 'd':
272                     db_printf("%11" DDB_EXPR_FMT "d", addr);
273                     break;
274           case 'u':
275                     db_printf("%11" DDB_EXPR_FMT "u", addr);
276                     break;
277           case 'o':
278                     db_printf("%15" DDB_EXPR_FMT "o", addr);
279                     break;
280           case 'c':
281                     value = addr & 0xFF;
282                     if (value >= ' ' && value <= '~')
283                               db_printf("%c", (char)value);
284                     else
285                               db_printf("\\%03o", (int)value);
286                     break;
287           }
288           db_printf("\n");
289 }
290 
291 void
db_print_loc_and_inst(db_addr_t loc)292 db_print_loc_and_inst(db_addr_t loc)
293 {
294 
295           db_printsym(loc, DB_STGY_PROC, db_printf);
296           db_printf(":\t");
297           (void) db_disasm(loc, false);
298 }
299 
300 /*
301  * Search for a value in memory.
302  * Syntax: search [/bhl] addr value [mask] [,count]
303  */
304 /*ARGSUSED*/
305 void
db_search_cmd(db_expr_t daddr,bool have_addr,db_expr_t dcount,const char * modif)306 db_search_cmd(db_expr_t daddr, bool have_addr,
307     db_expr_t dcount, const char *modif)
308 {
309           int                 t;
310           db_addr_t addr;
311           int                 size;
312           db_expr_t value;
313           db_expr_t mask;
314           db_expr_t count;
315 
316           t = db_read_token();
317           if (t == tSLASH) {
318                     t = db_read_token();
319                     if (t != tIDENT) {
320                               bad_modifier:
321                               db_printf("Bad modifier\n");
322                               db_flush_lex();
323                               return;
324                     }
325 
326                     if (!strcmp(db_tok_string, "b"))
327                               size = 1;
328                     else if (!strcmp(db_tok_string, "h"))
329                               size = 2;
330                     else if (!strcmp(db_tok_string, "l"))
331                               size = 4;
332                     else
333                               goto bad_modifier;
334           } else {
335                     db_unread_token(t);
336                     size = 4;
337           }
338 
339           if (!db_expression(&value)) {
340                     db_printf("Address missing\n");
341                     db_flush_lex();
342                     return;
343           }
344           addr = (db_addr_t) value;
345 
346           if (!db_expression(&value)) {
347                     db_printf("Value missing\n");
348                     db_flush_lex();
349                     return;
350           }
351 
352           if (!db_expression(&mask))
353                     mask = (int) ~0;
354 
355           t = db_read_token();
356           if (t == tCOMMA) {
357                     if (!db_expression(&count)) {
358                               db_printf("Count missing\n");
359                               db_flush_lex();
360                               return;
361                     }
362           } else {
363                     db_unread_token(t);
364                     count = -1;                   /* effectively forever */
365           }
366           db_skip_to_eol();
367 
368           db_search(addr, size, value, mask, count);
369 }
370 
371 static void
db_search(db_addr_t addr,int size,db_expr_t value,db_expr_t mask,unsigned int count)372 db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
373     unsigned int count)
374 {
375           while (count-- != 0) {
376                     db_prev = addr;
377                     if ((db_get_value(addr, size, false) & mask) == value)
378                               break;
379                     addr += size;
380           }
381           db_next = addr;
382 }
383