1*6e5e6fa9Sryo /* $NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo Exp $ */
2cf92afd6Scgd
361f28255Scgd /*
461f28255Scgd * Mach Operating System
561f28255Scgd * Copyright (c) 1991,1990 Carnegie Mellon University
661f28255Scgd * All Rights Reserved.
761f28255Scgd *
861f28255Scgd * Permission to use, copy, modify and distribute this software and its
961f28255Scgd * documentation is hereby granted, provided that both the copyright
1061f28255Scgd * notice and this permission notice appear in all copies of the
1161f28255Scgd * software, derivative works or modified versions, and any portions
1261f28255Scgd * thereof, and that both notices appear in supporting documentation.
1361f28255Scgd *
14b13e5d14Spk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1561f28255Scgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1661f28255Scgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1761f28255Scgd *
1861f28255Scgd * Carnegie Mellon requests users of this software to return to
1961f28255Scgd *
2061f28255Scgd * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
2161f28255Scgd * School of Computer Science
2261f28255Scgd * Carnegie Mellon University
2361f28255Scgd * Pittsburgh PA 15213-3890
2461f28255Scgd *
2561f28255Scgd * any improvements or extensions that they make and grant Carnegie the
2661f28255Scgd * rights to redistribute these changes.
2737cabe30Scgd *
2861f28255Scgd * Author: David B. Golub, Carnegie Mellon University
2961f28255Scgd * Date: 7/90
3061f28255Scgd */
31f1a5c330Smycroft
321ac69d9cSlukem #include <sys/cdefs.h>
33*6e5e6fa9Sryo __KERNEL_RCSID(0, "$NetBSD: db_examine.c,v 1.40 2019/09/12 09:20:23 ryo Exp $");
341ac69d9cSlukem
35f1a5c330Smycroft #include <sys/param.h>
36e4eb4c6cScgd #include <sys/systm.h>
37010ce493Spooka #include <sys/buf.h>
38f1a5c330Smycroft #include <sys/proc.h>
39f1a5c330Smycroft
40cd6b1c8fSad #include <ddb/ddb.h>
4161f28255Scgd
424eaa4d66Ssimonb static char db_examine_format[TOK_STRING_SIZE] = "x";
434eaa4d66Ssimonb
444eaa4d66Ssimonb static void db_examine(db_addr_t, char *, int);
454eaa4d66Ssimonb static void db_search(db_addr_t, int, db_expr_t, db_expr_t, unsigned int);
4661f28255Scgd
4761f28255Scgd /*
483e676d42Sgwr * Examine (print) data. Syntax is:
493e676d42Sgwr * x/[bhl][cdiorsuxz]*
503e676d42Sgwr * For example, the command:
513e676d42Sgwr * x/bxxxx
523e676d42Sgwr * should print:
533e676d42Sgwr * address: 01 23 45 67
5461f28255Scgd */
5561f28255Scgd /*ARGSUSED*/
5661f28255Scgd void
db_examine_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)5793feeb12Smatt db_examine_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
584d595fd7Schristos const char *modif)
5961f28255Scgd {
6061f28255Scgd if (modif[0] != '\0')
61f9121aadSitojun strlcpy(db_examine_format, modif, sizeof(db_examine_format));
6261f28255Scgd
6361f28255Scgd if (count == -1)
6461f28255Scgd count = 1;
6561f28255Scgd
6661f28255Scgd db_examine((db_addr_t) addr, db_examine_format, count);
6761f28255Scgd }
6861f28255Scgd
694eaa4d66Ssimonb static void
db_examine(db_addr_t addr,char * fmt,int count)704eaa4d66Ssimonb db_examine(db_addr_t addr, char *fmt, int count)
7161f28255Scgd {
725649071cSjmc int i, c;
73*6e5e6fa9Sryo quad_t value;
7461f28255Scgd int size;
7561f28255Scgd int width;
765649071cSjmc int bytes;
7761f28255Scgd char * fp;
78242cedc1Stv char tbuf[24];
7961f28255Scgd
8061f28255Scgd while (--count >= 0) {
8161f28255Scgd fp = fmt;
8261f28255Scgd size = 4;
8321a1e8e7Sgwr width = 12;
8461f28255Scgd while ((c = *fp++) != 0) {
85df82cd38Sgwr if (db_print_position() == 0) {
86df82cd38Sgwr /* Always print the address. */
87f3528d72Sjhawk db_printsym(addr, DB_STGY_ANY, db_printf);
88df82cd38Sgwr db_printf(":\t");
89df82cd38Sgwr db_prev = addr;
90df82cd38Sgwr }
9161f28255Scgd switch (c) {
92df82cd38Sgwr case 'b': /* byte */
9361f28255Scgd size = 1;
9461f28255Scgd width = 4;
9561f28255Scgd break;
96df82cd38Sgwr case 'h': /* half-word */
9761f28255Scgd size = 2;
9861f28255Scgd width = 8;
9961f28255Scgd break;
100df82cd38Sgwr case 'l': /* long-word */
10161f28255Scgd size = 4;
10221a1e8e7Sgwr width = 12;
10361f28255Scgd break;
10477e643c7Sryo case 'q': /* quad-word */
10577e643c7Sryo size = 8;
106*6e5e6fa9Sryo width = 24;
10777e643c7Sryo break;
10866ffb4e4Sross case 'L': /* implementation maximum */
10966ffb4e4Sross size = sizeof value;
11066ffb4e4Sross width = 12 * (sizeof value / 4);
11166ffb4e4Sross break;
11261f28255Scgd case 'a': /* address */
113c55851c8Sscw db_printf("= 0x%lx\n", (long)addr);
11461f28255Scgd break;
11531e239d6Sryo case 'p':
11631e239d6Sryo size = sizeof(void *);
117*6e5e6fa9Sryo value = db_get_value(addr, size, false);
11831e239d6Sryo addr += size;
11931e239d6Sryo db_printf("= 0x%lx ", (long)value);
12031e239d6Sryo db_printsym((db_addr_t)value, DB_STGY_ANY, db_printf);
12131e239d6Sryo db_printf("\n");
12231e239d6Sryo break;
12361f28255Scgd case 'r': /* signed, current radix */
124*6e5e6fa9Sryo value = db_get_qvalue(addr, size, true);
12561f28255Scgd addr += size;
1264f3d5a9cSthorpej db_format_radix(tbuf, 24, value, false);
127242cedc1Stv db_printf("%-*s", width, tbuf);
12861f28255Scgd break;
12961f28255Scgd case 'x': /* unsigned hex */
130*6e5e6fa9Sryo value = db_get_qvalue(addr, size, false);
13161f28255Scgd addr += size;
132*6e5e6fa9Sryo db_printf("%-*" PRIx64, width, value);
13361f28255Scgd break;
1345649071cSjmc case 'm': /* hex dump */
1355649071cSjmc /*
1365649071cSjmc * Print off in chunks of size. Try to print 16
137*6e5e6fa9Sryo * bytes at a time into 16/size columns. This
1385649071cSjmc * loops modify's count extra times in order
1395649071cSjmc * to get the nicely formatted lines.
1405649071cSjmc */
1415649071cSjmc
1425649071cSjmc bytes = 0;
1435649071cSjmc do {
1445649071cSjmc for (i = 0; i < size; i++) {
1455649071cSjmc value =
14677e643c7Sryo #if BYTE_ORDER == LITTLE_ENDIAN
14777e643c7Sryo db_get_value(addr +
14877e643c7Sryo (bytes & ~(size - 1)) +
14977e643c7Sryo size - i - 1, 1, false);
15077e643c7Sryo #else
15177e643c7Sryo db_get_value(addr + bytes,
15277e643c7Sryo 1, false);
15377e643c7Sryo #endif
15466cf68c4Sscw db_printf(
155*6e5e6fa9Sryo "%02" PRIx64,
156a2bf8e5dSjoerg value);
1575649071cSjmc bytes++;
15877e643c7Sryo if (!(bytes % size))
1595649071cSjmc db_printf(" ");
1605649071cSjmc }
1615649071cSjmc } while ((bytes != 16) && count--);
1625649071cSjmc /* True up the columns before continuing */
1635649071cSjmc for (i = 4; i >= (bytes / 4); i--)
1645649071cSjmc db_printf ("\t");
1655649071cSjmc /* Print chars, use . for non-printable's. */
1665649071cSjmc while (bytes--) {
1674f3d5a9cSthorpej value = db_get_value(addr, 1, false);
1685649071cSjmc addr += 1;
1695649071cSjmc if (value >= ' ' && value <= '~')
1705649071cSjmc db_printf("%c", (char)value);
1715649071cSjmc else
1725649071cSjmc db_printf(".");
1735649071cSjmc }
1745649071cSjmc db_printf("\n");
1755649071cSjmc break;
17661f28255Scgd case 'z': /* signed hex */
177*6e5e6fa9Sryo value = db_get_qvalue(addr, size, true);
17861f28255Scgd addr += size;
1794f3d5a9cSthorpej db_format_hex(tbuf, 24, value, false);
180242cedc1Stv db_printf("%-*s", width, tbuf);
18161f28255Scgd break;
18261f28255Scgd case 'd': /* signed decimal */
183*6e5e6fa9Sryo value = db_get_qvalue(addr, size, true);
18461f28255Scgd addr += size;
185*6e5e6fa9Sryo db_printf("%-*" PRId64, width, value);
18661f28255Scgd break;
18761f28255Scgd case 'u': /* unsigned decimal */
188*6e5e6fa9Sryo value = db_get_qvalue(addr, size, false);
18961f28255Scgd addr += size;
190*6e5e6fa9Sryo db_printf("%-*" PRIu64, width, value);
19161f28255Scgd break;
19261f28255Scgd case 'o': /* unsigned octal */
193*6e5e6fa9Sryo value = db_get_qvalue(addr, size, false);
19461f28255Scgd addr += size;
195*6e5e6fa9Sryo db_printf("%-*" PRIo64, width, value);
19661f28255Scgd break;
19761f28255Scgd case 'c': /* character */
1984f3d5a9cSthorpej value = db_get_value(addr, 1, false);
19961f28255Scgd addr += 1;
20061f28255Scgd if (value >= ' ' && value <= '~')
20112da023cSmycroft db_printf("%c", (char)value);
20261f28255Scgd else
20366cf68c4Sscw db_printf("\\%03o", (int)value);
20461f28255Scgd break;
20561f28255Scgd case 's': /* null-terminated string */
20661f28255Scgd for (;;) {
2074f3d5a9cSthorpej value = db_get_value(addr, 1, false);
20861f28255Scgd addr += 1;
20961f28255Scgd if (value == 0)
21061f28255Scgd break;
21161f28255Scgd if (value >= ' ' && value <= '~')
21212da023cSmycroft db_printf("%c", (char)value);
21361f28255Scgd else
21466cf68c4Sscw db_printf("\\%03o", (int)value);
21561f28255Scgd }
21661f28255Scgd break;
21761f28255Scgd case 'i': /* instruction */
2184f3d5a9cSthorpej addr = db_disasm(addr, false);
21961f28255Scgd break;
22061f28255Scgd case 'I': /* instruction, alternate form */
2214f3d5a9cSthorpej addr = db_disasm(addr, true);
22261f28255Scgd break;
22361f28255Scgd default:
22461f28255Scgd break;
22561f28255Scgd }
22661f28255Scgd if (db_print_position() != 0)
22761f28255Scgd db_end_line();
22861f28255Scgd }
22961f28255Scgd }
23061f28255Scgd db_next = addr;
23161f28255Scgd }
23261f28255Scgd
23361f28255Scgd /*
23461f28255Scgd * Print value.
23561f28255Scgd */
2364eaa4d66Ssimonb static char db_print_format = 'x';
23761f28255Scgd
23861f28255Scgd /*ARGSUSED*/
23961f28255Scgd void
db_print_cmd(db_expr_t addr,bool have_addr,db_expr_t count,const char * modif)24093feeb12Smatt db_print_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
2414d595fd7Schristos const char *modif)
24261f28255Scgd {
24361f28255Scgd db_expr_t value;
24461f28255Scgd
24561f28255Scgd if (modif[0] != '\0')
24661f28255Scgd db_print_format = modif[0];
24761f28255Scgd
24861f28255Scgd switch (db_print_format) {
24961f28255Scgd case 'a':
250f3528d72Sjhawk db_printsym((db_addr_t)addr, DB_STGY_ANY, db_printf);
25161f28255Scgd break;
25261f28255Scgd case 'r':
253242cedc1Stv {
254242cedc1Stv char tbuf[24];
255242cedc1Stv
2564f3d5a9cSthorpej db_format_radix(tbuf, 24, addr, false);
257242cedc1Stv db_printf("%11s", tbuf);
25861f28255Scgd break;
259242cedc1Stv }
26061f28255Scgd case 'x':
261a2bf8e5dSjoerg db_printf("%16" DDB_EXPR_FMT "x", addr);
26261f28255Scgd break;
26361f28255Scgd case 'z':
264242cedc1Stv {
265242cedc1Stv char tbuf[24];
266242cedc1Stv
2674f3d5a9cSthorpej db_format_hex(tbuf, 24, addr, false);
268242cedc1Stv db_printf("%8s", tbuf);
26961f28255Scgd break;
270242cedc1Stv }
27161f28255Scgd case 'd':
272a2bf8e5dSjoerg db_printf("%11" DDB_EXPR_FMT "d", addr);
27361f28255Scgd break;
27461f28255Scgd case 'u':
275a2bf8e5dSjoerg db_printf("%11" DDB_EXPR_FMT "u", addr);
27661f28255Scgd break;
27761f28255Scgd case 'o':
278a2bf8e5dSjoerg db_printf("%15" DDB_EXPR_FMT "o", addr);
27961f28255Scgd break;
28061f28255Scgd case 'c':
28161f28255Scgd value = addr & 0xFF;
28261f28255Scgd if (value >= ' ' && value <= '~')
28312da023cSmycroft db_printf("%c", (char)value);
28461f28255Scgd else
28566cf68c4Sscw db_printf("\\%03o", (int)value);
28661f28255Scgd break;
28761f28255Scgd }
28861f28255Scgd db_printf("\n");
28961f28255Scgd }
29061f28255Scgd
2918c2e3b4bSchristos void
db_print_loc_and_inst(db_addr_t loc)2924eaa4d66Ssimonb db_print_loc_and_inst(db_addr_t loc)
29361f28255Scgd {
2944eaa4d66Ssimonb
295f3528d72Sjhawk db_printsym(loc, DB_STGY_PROC, db_printf);
29661f28255Scgd db_printf(":\t");
2974f3d5a9cSthorpej (void) db_disasm(loc, false);
29861f28255Scgd }
29961f28255Scgd
30061f28255Scgd /*
30161f28255Scgd * Search for a value in memory.
30261f28255Scgd * Syntax: search [/bhl] addr value [mask] [,count]
30361f28255Scgd */
3048c2e3b4bSchristos /*ARGSUSED*/
30561f28255Scgd void
db_search_cmd(db_expr_t daddr,bool have_addr,db_expr_t dcount,const char * modif)30693feeb12Smatt db_search_cmd(db_expr_t daddr, bool have_addr,
307168cd830Schristos db_expr_t dcount, const char *modif)
30861f28255Scgd {
30961f28255Scgd int t;
31061f28255Scgd db_addr_t addr;
31161f28255Scgd int size;
31261f28255Scgd db_expr_t value;
31361f28255Scgd db_expr_t mask;
31465a65d45Scgd db_expr_t count;
31561f28255Scgd
31661f28255Scgd t = db_read_token();
31761f28255Scgd if (t == tSLASH) {
31861f28255Scgd t = db_read_token();
31961f28255Scgd if (t != tIDENT) {
32061f28255Scgd bad_modifier:
32161f28255Scgd db_printf("Bad modifier\n");
32261f28255Scgd db_flush_lex();
32361f28255Scgd return;
32461f28255Scgd }
32561f28255Scgd
32661f28255Scgd if (!strcmp(db_tok_string, "b"))
32761f28255Scgd size = 1;
32861f28255Scgd else if (!strcmp(db_tok_string, "h"))
32961f28255Scgd size = 2;
33061f28255Scgd else if (!strcmp(db_tok_string, "l"))
33161f28255Scgd size = 4;
33261f28255Scgd else
33361f28255Scgd goto bad_modifier;
33461f28255Scgd } else {
33561f28255Scgd db_unread_token(t);
33661f28255Scgd size = 4;
33761f28255Scgd }
33861f28255Scgd
3398c2e3b4bSchristos if (!db_expression(&value)) {
34061f28255Scgd db_printf("Address missing\n");
34161f28255Scgd db_flush_lex();
34261f28255Scgd return;
34361f28255Scgd }
3448c2e3b4bSchristos addr = (db_addr_t) value;
34561f28255Scgd
34661f28255Scgd if (!db_expression(&value)) {
34761f28255Scgd db_printf("Value missing\n");
34861f28255Scgd db_flush_lex();
34961f28255Scgd return;
35061f28255Scgd }
35161f28255Scgd
35261f28255Scgd if (!db_expression(&mask))
3538c2e3b4bSchristos mask = (int) ~0;
35461f28255Scgd
35561f28255Scgd t = db_read_token();
35661f28255Scgd if (t == tCOMMA) {
35761f28255Scgd if (!db_expression(&count)) {
35861f28255Scgd db_printf("Count missing\n");
35961f28255Scgd db_flush_lex();
36061f28255Scgd return;
36161f28255Scgd }
36261f28255Scgd } else {
36361f28255Scgd db_unread_token(t);
36461f28255Scgd count = -1; /* effectively forever */
36561f28255Scgd }
36661f28255Scgd db_skip_to_eol();
36761f28255Scgd
36861f28255Scgd db_search(addr, size, value, mask, count);
36961f28255Scgd }
37061f28255Scgd
3714eaa4d66Ssimonb static void
db_search(db_addr_t addr,int size,db_expr_t value,db_expr_t mask,unsigned int count)3724eaa4d66Ssimonb db_search(db_addr_t addr, int size, db_expr_t value, db_expr_t mask,
3734eaa4d66Ssimonb unsigned int count)
37461f28255Scgd {
37561f28255Scgd while (count-- != 0) {
37661f28255Scgd db_prev = addr;
3774f3d5a9cSthorpej if ((db_get_value(addr, size, false) & mask) == value)
37861f28255Scgd break;
37961f28255Scgd addr += size;
38061f28255Scgd }
38161f28255Scgd db_next = addr;
38261f28255Scgd }
383