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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * MDB Target Layer
28 *
29 * The *target* is the program being inspected by the debugger. The MDB target
30 * layer provides a set of functions that insulate common debugger code,
31 * including the MDB Module API, from the implementation details of how the
32 * debugger accesses information from a given target. Each target exports a
33 * standard set of properties, including one or more address spaces, one or
34 * more symbol tables, a set of load objects, and a set of threads that can be
35 * examined using the interfaces in <mdb/mdb_target.h>. This technique has
36 * been employed successfully in other debuggers, including [1], primarily
37 * to improve portability, although the term "target" often refers to the
38 * encapsulation of architectural or operating system-specific details. The
39 * target abstraction is useful for MDB because it allows us to easily extend
40 * the debugger to examine a variety of different program forms. Primarily,
41 * the target functions validate input arguments and then call an appropriate
42 * function in the target ops vector, defined in <mdb/mdb_target_impl.h>.
43 * However, this interface layer provides a very high level of flexibility for
165 #include <strings.h>
166 #include <stdlib.h>
167 #include <errno.h>
168
169 /*
170 * Define convenience macros for referencing the set of vespec flag bits that
171 * are preserved by the target implementation, and the set of bits that
172 * determine automatic ve_hits == ve_limit behavior.
173 */
174 #define T_IMPL_BITS \
175 (MDB_TGT_SPEC_INTERNAL | MDB_TGT_SPEC_SILENT | MDB_TGT_SPEC_MATCHED | \
176 MDB_TGT_SPEC_DELETED)
177
178 #define T_AUTO_BITS \
179 (MDB_TGT_SPEC_AUTOSTOP | MDB_TGT_SPEC_AUTODEL | MDB_TGT_SPEC_AUTODIS)
180
181 /*
182 * Define convenience macro for referencing target flag pending continue bits.
183 */
184 #define T_CONT_BITS \
185 (MDB_TGT_F_STEP | MDB_TGT_F_STEP_OUT | MDB_TGT_F_STEP_BRANCH | \
186 MDB_TGT_F_NEXT | MDB_TGT_F_CONT)
187
188 mdb_tgt_t *
189 mdb_tgt_create(mdb_tgt_ctor_f *ctor, int flags, int argc, const char *argv[])
190 {
191 mdb_module_t *mp;
192 mdb_tgt_t *t;
193
194 if (flags & ~MDB_TGT_F_ALL) {
195 (void) set_errno(EINVAL);
196 return (NULL);
197 }
198
199 t = mdb_zalloc(sizeof (mdb_tgt_t), UM_SLEEP);
200 mdb_list_append(&mdb.m_tgtlist, t);
201
202 t->t_module = &mdb.m_rmod;
203 t->t_matched = T_SE_END;
204 t->t_flags = flags;
205 t->t_vepos = 1;
206 t->t_veneg = 1;
1071 /*
1072 * If the target is undead, dead, or lost, we no longer allow continue.
1073 * This effectively forces the user to use ::kill or ::run after death.
1074 */
1075 if (t->t_status.st_state == MDB_TGT_UNDEAD)
1076 return (set_errno(EMDB_TGTZOMB));
1077 if (t->t_status.st_state == MDB_TGT_DEAD)
1078 return (set_errno(EMDB_TGTCORE));
1079 if (t->t_status.st_state == MDB_TGT_LOST)
1080 return (set_errno(EMDB_TGTLOST));
1081
1082 /*
1083 * If any of single-step, step-over, or step-out is pending, it takes
1084 * precedence over an explicit or pending continue, because these are
1085 * all different specialized forms of continue.
1086 */
1087 if (t->t_flags & MDB_TGT_F_STEP)
1088 t_cont = t->t_ops->t_step;
1089 else if (t->t_flags & MDB_TGT_F_NEXT)
1090 t_cont = t->t_ops->t_step;
1091 else if (t->t_flags & MDB_TGT_F_STEP_BRANCH)
1092 t_cont = t->t_ops->t_cont;
1093 else if (t->t_flags & MDB_TGT_F_STEP_OUT)
1094 t_cont = t->t_ops->t_cont;
1095
1096 /*
1097 * To handle step-over, we ask the target to find the address past the
1098 * next control transfer instruction. If an address is found, we plant
1099 * a temporary breakpoint there and continue; otherwise just step.
1100 */
1101 if ((t->t_flags & MDB_TGT_F_NEXT) && !(t->t_flags & MDB_TGT_F_STEP)) {
1102 if (t->t_ops->t_next(t, &addr) == -1 || mdb_tgt_add_vbrkpt(t,
1103 addr, MDB_TGT_SPEC_HIDDEN | MDB_TGT_SPEC_TEMPORARY,
1104 no_se_f, NULL) == 0) {
1105 mdb_dprintf(MDB_DBG_TGT, "next falling back to step: "
1106 "%s\n", mdb_strerror(errno));
1107 } else
1108 t_cont = t->t_ops->t_cont;
1109 }
1110
1111 /*
1112 * To handle step-out, we ask the target to find the return address of
1113 * the current frame, plant a temporary breakpoint there, and continue.
1114 */
1115 if (t->t_flags & MDB_TGT_F_STEP_OUT) {
1116 if (t->t_ops->t_step_out(t, &addr) == -1)
1117 return (-1); /* errno is set for us */
1118
1119 if (mdb_tgt_add_vbrkpt(t, addr, MDB_TGT_SPEC_HIDDEN |
1120 MDB_TGT_SPEC_TEMPORARY, no_se_f, NULL) == 0)
1121 return (-1); /* errno is set for us */
1122 }
1123
1124 /*
1125 * To handle step-branch, we ask the target to enable it for the coming
1126 * continue. Step-branch is incompatible with step, so don't enable it
1127 * if we're going to be stepping.
1128 */
1129 if (t->t_flags & MDB_TGT_F_STEP_BRANCH && t_cont == t->t_ops->t_cont) {
1130 if (t->t_ops->t_step_branch(t) == -1)
1131 return (-1); /* errno is set for us */
1132 }
1133
1134 (void) mdb_signal_block(SIGHUP);
1135 (void) mdb_signal_block(SIGTERM);
1136 mdb_intr_disable();
1137
1138 t->t_flags &= ~T_CONT_BITS;
1139 t->t_flags |= MDB_TGT_F_BUSY;
1140 mdb_tgt_sespec_arm_all(t);
1141
1142 ASSERT(t->t_matched != NULL);
1143 matched = t->t_matched;
1144 t->t_matched = T_SE_END;
1145
1146 if (mdb.m_term != NULL)
1147 IOP_SUSPEND(mdb.m_term);
1148
1149 /*
1150 * Iterate over the matched sespec list, performing autostop processing
1151 * and clearing the matched bit for each associated vespec. We then
1152 * invoke each sespec's se_cont callback in order to continue past
1153 * the corresponding event. If the matched list has more than one
1377 (void) mdb_tgt_sespec_activate_all(t);
1378
1379 if (mdb.m_term != NULL)
1380 IOP_CTL(mdb.m_term, MDB_IOC_CTTY, NULL);
1381
1382 return (0);
1383 }
1384
1385 int
1386 mdb_tgt_step(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1387 {
1388 return (tgt_request_continue(t, tsp, MDB_TGT_F_STEP, t->t_ops->t_step));
1389 }
1390
1391 int
1392 mdb_tgt_step_out(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1393 {
1394 t->t_flags |= MDB_TGT_F_STEP_OUT; /* set flag even if tgt not busy */
1395 return (tgt_request_continue(t, tsp, 0, t->t_ops->t_cont));
1396 }
1397
1398 int
1399 mdb_tgt_step_branch(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1400 {
1401 t->t_flags |= MDB_TGT_F_STEP_BRANCH; /* set flag even if tgt not busy */
1402 return (tgt_request_continue(t, tsp, 0, t->t_ops->t_cont));
1403 }
1404
1405 int
1406 mdb_tgt_next(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1407 {
1408 t->t_flags |= MDB_TGT_F_NEXT; /* set flag even if tgt not busy */
1409 return (tgt_request_continue(t, tsp, 0, t->t_ops->t_step));
1410 }
1411
1412 int
1413 mdb_tgt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1414 {
1415 return (tgt_request_continue(t, tsp, MDB_TGT_F_CONT, t->t_ops->t_cont));
1416 }
1417
1418 int
1419 mdb_tgt_signal(mdb_tgt_t *t, int sig)
1420 {
1421 return (t->t_ops->t_signal(t, sig));
1422 }
1423
|
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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2018 Joyent, Inc.
26 */
27
28 /*
29 * MDB Target Layer
30 *
31 * The *target* is the program being inspected by the debugger. The MDB target
32 * layer provides a set of functions that insulate common debugger code,
33 * including the MDB Module API, from the implementation details of how the
34 * debugger accesses information from a given target. Each target exports a
35 * standard set of properties, including one or more address spaces, one or
36 * more symbol tables, a set of load objects, and a set of threads that can be
37 * examined using the interfaces in <mdb/mdb_target.h>. This technique has
38 * been employed successfully in other debuggers, including [1], primarily
39 * to improve portability, although the term "target" often refers to the
40 * encapsulation of architectural or operating system-specific details. The
41 * target abstraction is useful for MDB because it allows us to easily extend
42 * the debugger to examine a variety of different program forms. Primarily,
43 * the target functions validate input arguments and then call an appropriate
44 * function in the target ops vector, defined in <mdb/mdb_target_impl.h>.
45 * However, this interface layer provides a very high level of flexibility for
167 #include <strings.h>
168 #include <stdlib.h>
169 #include <errno.h>
170
171 /*
172 * Define convenience macros for referencing the set of vespec flag bits that
173 * are preserved by the target implementation, and the set of bits that
174 * determine automatic ve_hits == ve_limit behavior.
175 */
176 #define T_IMPL_BITS \
177 (MDB_TGT_SPEC_INTERNAL | MDB_TGT_SPEC_SILENT | MDB_TGT_SPEC_MATCHED | \
178 MDB_TGT_SPEC_DELETED)
179
180 #define T_AUTO_BITS \
181 (MDB_TGT_SPEC_AUTOSTOP | MDB_TGT_SPEC_AUTODEL | MDB_TGT_SPEC_AUTODIS)
182
183 /*
184 * Define convenience macro for referencing target flag pending continue bits.
185 */
186 #define T_CONT_BITS \
187 (MDB_TGT_F_STEP | MDB_TGT_F_STEP_OUT | MDB_TGT_F_NEXT | MDB_TGT_F_CONT)
188
189 mdb_tgt_t *
190 mdb_tgt_create(mdb_tgt_ctor_f *ctor, int flags, int argc, const char *argv[])
191 {
192 mdb_module_t *mp;
193 mdb_tgt_t *t;
194
195 if (flags & ~MDB_TGT_F_ALL) {
196 (void) set_errno(EINVAL);
197 return (NULL);
198 }
199
200 t = mdb_zalloc(sizeof (mdb_tgt_t), UM_SLEEP);
201 mdb_list_append(&mdb.m_tgtlist, t);
202
203 t->t_module = &mdb.m_rmod;
204 t->t_matched = T_SE_END;
205 t->t_flags = flags;
206 t->t_vepos = 1;
207 t->t_veneg = 1;
1072 /*
1073 * If the target is undead, dead, or lost, we no longer allow continue.
1074 * This effectively forces the user to use ::kill or ::run after death.
1075 */
1076 if (t->t_status.st_state == MDB_TGT_UNDEAD)
1077 return (set_errno(EMDB_TGTZOMB));
1078 if (t->t_status.st_state == MDB_TGT_DEAD)
1079 return (set_errno(EMDB_TGTCORE));
1080 if (t->t_status.st_state == MDB_TGT_LOST)
1081 return (set_errno(EMDB_TGTLOST));
1082
1083 /*
1084 * If any of single-step, step-over, or step-out is pending, it takes
1085 * precedence over an explicit or pending continue, because these are
1086 * all different specialized forms of continue.
1087 */
1088 if (t->t_flags & MDB_TGT_F_STEP)
1089 t_cont = t->t_ops->t_step;
1090 else if (t->t_flags & MDB_TGT_F_NEXT)
1091 t_cont = t->t_ops->t_step;
1092 else if (t->t_flags & MDB_TGT_F_STEP_OUT)
1093 t_cont = t->t_ops->t_cont;
1094
1095 /*
1096 * To handle step-over, we ask the target to find the address past the
1097 * next control transfer instruction. If an address is found, we plant
1098 * a temporary breakpoint there and continue; otherwise just step.
1099 */
1100 if ((t->t_flags & MDB_TGT_F_NEXT) && !(t->t_flags & MDB_TGT_F_STEP)) {
1101 if (t->t_ops->t_next(t, &addr) == -1 || mdb_tgt_add_vbrkpt(t,
1102 addr, MDB_TGT_SPEC_HIDDEN | MDB_TGT_SPEC_TEMPORARY,
1103 no_se_f, NULL) == 0) {
1104 mdb_dprintf(MDB_DBG_TGT, "next falling back to step: "
1105 "%s\n", mdb_strerror(errno));
1106 } else
1107 t_cont = t->t_ops->t_cont;
1108 }
1109
1110 /*
1111 * To handle step-out, we ask the target to find the return address of
1112 * the current frame, plant a temporary breakpoint there, and continue.
1113 */
1114 if (t->t_flags & MDB_TGT_F_STEP_OUT) {
1115 if (t->t_ops->t_step_out(t, &addr) == -1)
1116 return (-1); /* errno is set for us */
1117
1118 if (mdb_tgt_add_vbrkpt(t, addr, MDB_TGT_SPEC_HIDDEN |
1119 MDB_TGT_SPEC_TEMPORARY, no_se_f, NULL) == 0)
1120 return (-1); /* errno is set for us */
1121 }
1122
1123 (void) mdb_signal_block(SIGHUP);
1124 (void) mdb_signal_block(SIGTERM);
1125 mdb_intr_disable();
1126
1127 t->t_flags &= ~T_CONT_BITS;
1128 t->t_flags |= MDB_TGT_F_BUSY;
1129 mdb_tgt_sespec_arm_all(t);
1130
1131 ASSERT(t->t_matched != NULL);
1132 matched = t->t_matched;
1133 t->t_matched = T_SE_END;
1134
1135 if (mdb.m_term != NULL)
1136 IOP_SUSPEND(mdb.m_term);
1137
1138 /*
1139 * Iterate over the matched sespec list, performing autostop processing
1140 * and clearing the matched bit for each associated vespec. We then
1141 * invoke each sespec's se_cont callback in order to continue past
1142 * the corresponding event. If the matched list has more than one
1366 (void) mdb_tgt_sespec_activate_all(t);
1367
1368 if (mdb.m_term != NULL)
1369 IOP_CTL(mdb.m_term, MDB_IOC_CTTY, NULL);
1370
1371 return (0);
1372 }
1373
1374 int
1375 mdb_tgt_step(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1376 {
1377 return (tgt_request_continue(t, tsp, MDB_TGT_F_STEP, t->t_ops->t_step));
1378 }
1379
1380 int
1381 mdb_tgt_step_out(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1382 {
1383 t->t_flags |= MDB_TGT_F_STEP_OUT; /* set flag even if tgt not busy */
1384 return (tgt_request_continue(t, tsp, 0, t->t_ops->t_cont));
1385 }
1386
1387 int
1388 mdb_tgt_next(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1389 {
1390 t->t_flags |= MDB_TGT_F_NEXT; /* set flag even if tgt not busy */
1391 return (tgt_request_continue(t, tsp, 0, t->t_ops->t_step));
1392 }
1393
1394 int
1395 mdb_tgt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
1396 {
1397 return (tgt_request_continue(t, tsp, MDB_TGT_F_CONT, t->t_ops->t_cont));
1398 }
1399
1400 int
1401 mdb_tgt_signal(mdb_tgt_t *t, int sig)
1402 {
1403 return (t->t_ops->t_signal(t, sig));
1404 }
1405
|