1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2018 Joyent, Inc.
26 * Copyright 2024 Oxide Computer Company
27 */
28
29 /*
30 * Immediate Value Target
31 *
32 * The immediate value target is used when the '=' verb is used to
33 * format an immediate value, or with ::print -i. The target is
34 * initialized with a specific value, and then simply copies bytes from
35 * this integer in its read routine. Two notes:
36 *
37 * (1) the address parameter of value_read is treated as an offset into
38 * the immediate value.
39 *
40 * (2) on big-endian systems, we need to be careful about the place we
41 * copy data from. If the caller specified a typesize in the argv array
42 * we use that for offsetting, otherwise we use the read size.
43 * If the user didn't specify the typesize, then 'addr' is ignored,
44 * and all reads are at an offset of 0 into the immediate value. This
45 * covers both the usage of ::print -i, and the semantics of adb
46 * commands like "0x1234=X", which should produce 0x1234 as a result;
47 * the adb model is for it to act like a cast down to the smaller
48 * integer type; this is handled as mentioned.
49 */
50
51 #include <mdb/mdb_target_impl.h>
52 #include <mdb/mdb_types.h>
53 #include <mdb/mdb_conf.h>
54 #include <mdb/mdb_err.h>
55
56 #include <sys/isa_defs.h>
57 #include <strings.h>
58
59 void mdb_value_tgt_destroy(mdb_tgt_t *);
60
61 typedef struct mdb_value_data {
62 uintmax_t mvd_data;
63 size_t mvd_typesize;
64 } mdb_value_data_t;
65
66 static ssize_t
value_read(mdb_tgt_t * t,void * dst,size_t nbytes,uintptr_t addr)67 value_read(mdb_tgt_t *t, void *dst, size_t nbytes, uintptr_t addr)
68 {
69 mdb_value_data_t *data = t->t_data;
70 size_t size = data->mvd_typesize;
71 const char *src = (const char *)&data->mvd_data;
72 size_t off;
73
74 /*
75 * If no output size was specified, use the current read size.
76 * In this case, "addr" is not an offset into the mvd_data,
77 * so we ignore it.
78 */
79 if (size == 0) {
80 size = nbytes;
81 addr = 0;
82 } else {
83 nbytes = MIN(size, nbytes);
84 }
85
86 off = addr;
87 #ifdef _BIG_ENDIAN
88 if (sizeof (uintmax_t) >= size)
89 off += sizeof (uintmax_t) - size;
90 #endif
91
92 if (off > sizeof (uintmax_t))
93 return (0);
94 if (off + nbytes > sizeof (uintmax_t))
95 nbytes = sizeof (uintmax_t) - off;
96
97 if (nbytes != 0)
98 bcopy(src + off, dst, nbytes);
99
100 return (nbytes);
101 }
102
103 /*ARGSUSED*/
104 static ssize_t
value_write(mdb_tgt_t * t,const void * buf,size_t nbytes,uintptr_t addr)105 value_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
106 {
107 return (nbytes); /* We allow writes to silently fail */
108 }
109
110 static const mdb_tgt_ops_t value_ops = {
111 .t_setflags = (int (*)())(uintptr_t)mdb_tgt_notsup,
112 .t_setcontext = (int (*)())(uintptr_t)mdb_tgt_notsup,
113 .t_activate = (void (*)())(uintptr_t)mdb_tgt_nop,
114 .t_deactivate = (void (*)())(uintptr_t)mdb_tgt_nop,
115 .t_periodic = (void (*)())(uintptr_t)mdb_tgt_nop,
116 .t_destroy = mdb_value_tgt_destroy,
117 .t_name = (const char *(*)())mdb_tgt_null,
118 .t_isa = (const char *(*)())mdb_conf_isa,
119 .t_platform = (const char *(*)())mdb_conf_platform,
120 .t_uname = (int (*)())(uintptr_t)mdb_tgt_notsup,
121 .t_dmodel = (int (*)())(uintptr_t)mdb_tgt_notsup,
122 .t_aread = (ssize_t (*)())mdb_tgt_notsup,
123 .t_awrite = (ssize_t (*)())mdb_tgt_notsup,
124 .t_vread = value_read,
125 .t_vwrite = value_write,
126 .t_pread = (ssize_t (*)())mdb_tgt_notsup,
127 .t_pwrite = (ssize_t (*)())mdb_tgt_notsup,
128 .t_fread = value_read,
129 .t_fwrite = value_write,
130 .t_ioread = value_read,
131 .t_iowrite = value_write,
132 .t_vtop = (int (*)())(uintptr_t)mdb_tgt_notsup,
133 .t_lookup_by_name = (int (*)())(uintptr_t)mdb_tgt_notsup,
134 .t_lookup_by_addr = (int (*)())(uintptr_t)mdb_tgt_notsup,
135 .t_symbol_iter = (int (*)())(uintptr_t)mdb_tgt_notsup,
136 .t_mapping_iter = (int (*)())(uintptr_t)mdb_tgt_notsup,
137 .t_object_iter = (int (*)())(uintptr_t)mdb_tgt_notsup,
138 .t_addr_to_map = (const mdb_map_t *(*)())mdb_tgt_null,
139 .t_name_to_map = (const mdb_map_t *(*)())mdb_tgt_null,
140 .t_addr_to_ctf = (struct ctf_file *(*)())mdb_tgt_null,
141 .t_name_to_ctf = (struct ctf_file *(*)())mdb_tgt_null,
142 .t_status = (int (*)())(uintptr_t)mdb_tgt_notsup,
143 .t_run = (int (*)())(uintptr_t)mdb_tgt_notsup,
144 .t_step = (int (*)())(uintptr_t)mdb_tgt_notsup,
145 .t_step_out = (int (*)())(uintptr_t)mdb_tgt_notsup,
146 .t_next = (int (*)())(uintptr_t)mdb_tgt_notsup,
147 .t_cont = (int (*)())(uintptr_t)mdb_tgt_notsup,
148 .t_signal = (int (*)())(uintptr_t)mdb_tgt_notsup,
149 .t_add_vbrkpt = (int (*)())(uintptr_t)mdb_tgt_null,
150 .t_add_sbrkpt = (int (*)())(uintptr_t)mdb_tgt_null,
151 .t_add_pwapt = (int (*)())(uintptr_t)mdb_tgt_null,
152 .t_add_vwapt = (int (*)())(uintptr_t)mdb_tgt_null,
153 .t_add_iowapt = (int (*)())(uintptr_t)mdb_tgt_null,
154 .t_add_sysenter = (int (*)())(uintptr_t)mdb_tgt_null,
155 .t_add_sysexit = (int (*)())(uintptr_t)mdb_tgt_null,
156 .t_add_signal = (int (*)())(uintptr_t)mdb_tgt_null,
157 .t_add_fault = (int (*)())(uintptr_t)mdb_tgt_null,
158 .t_getareg = (int (*)())(uintptr_t)mdb_tgt_notsup,
159 .t_putareg = (int (*)())(uintptr_t)mdb_tgt_notsup,
160 .t_stack_iter = (int (*)())(uintptr_t)mdb_tgt_nop,
161 .t_auxv = (int (*)())(uintptr_t)mdb_tgt_notsup,
162 .t_thread_name = (int (*)())(uintptr_t)mdb_tgt_notsup,
163 };
164
165 int
mdb_value_tgt_create(mdb_tgt_t * t,int argc,const char * argv[])166 mdb_value_tgt_create(mdb_tgt_t *t, int argc, const char *argv[])
167 {
168 mdb_value_data_t *data;
169
170 if (argc < 1 || argv[0] == NULL)
171 return (set_errno(EINVAL));
172 if (argc == 2 && argv[1] == NULL)
173 return (set_errno(EINVAL));
174 if (argc > 2)
175 return (set_errno(EINVAL));
176
177 t->t_ops = &value_ops;
178 data = mdb_zalloc(sizeof (mdb_value_data_t), UM_SLEEP);
179 t->t_data = data;
180 data->mvd_data = *((uintmax_t *)(void *)argv[0]);
181 if (argc == 2)
182 data->mvd_typesize = *((size_t *)(void *)argv[1]);
183
184 return (0);
185 }
186
187 void
mdb_value_tgt_destroy(mdb_tgt_t * t)188 mdb_value_tgt_destroy(mdb_tgt_t *t)
189 {
190 mdb_free(t->t_data, sizeof (mdb_value_data_t));
191 }
192