4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * In order to implement walk iteration variables (that is, ::walk walk varname)
31 * we need to keep track of the active walk variables as the pipeline is
32 * processed. Each variable is tracked using a VCB (Variable Control Block)
33 * that keeps a pointer to the variable in the MDB variable hash table, as
34 * well as an addrvec (array of values) and parent pointer. Each command in
35 * the pipeline keeps its own list of VCBs, and these are inherited from left
36 * to right in the pipeline. The diagram shows an example pipeline and the
37 * contents of c_addrv and VCBs at each stage:
39 * > ::walk proc p | ::map .+1 | ::eval '<p=K'
42 * 0<- parent <----------- parent
43 * c_addrv addrv c_addrv addrv
48 * Then the first command (::walk) begins life with no VCBs. It then creates
49 * a new VCB for the rest of the pipeline and adds it to the next command's
50 * VCB list (::map). Before ::map is executed, it will first pass along a set
51 * of VCBs to its "child" ::eval. The important operations defined for VCBs
54 * (1) mdb_vcb_inherit - Prior to processing each command (pipeline stage), the
55 * debugger calls the inherit routine to cause the next command to inherit the
56 * VCBs from the current command. The inherit routine allocates a new VCB
57 * containing a pointer to the same variable, and sets its parent pointer to
58 * point back to the parent VCB. A VCB created by ::walk has a NULL parent
59 * pointer indicating that it inherits its value from dot.
61 * (2) mdb_vcb_propagate - Prior to invoking the dcmd associated with a command,
62 * the debugger propagates the next value stored in the VCB to its variable.
63 * The VCB stores the values the variable should assume (that is, the values
64 * of the variable that correspond to the value stored in the command's c_addrv)
65 * in an addrvec in the VCB itself.
67 * (3) mdb_vcb_update - As each dcmd executes, it produces output for the next
68 * stage in the pipeline. The *next* stage of the pipeline's mdb_cmd_t has
69 * already inherited the necessary VCBs in step (1), and so we just need to
70 * record the current value of the variable into the VCB's addrv. In the base
71 * case (the first pipeline stage), the variable is not yet set, so we want
72 * to store the current value of dot (produced by ::walk's callback) into the
73 * addrv. This value is passed in directly from the parsing code as a parameter
74 * before the parser resets dot itself. For subsequent pipeline stages, we
75 * need to store into addrv the value the variable previously held when the
76 * dcmd that produced this new value of dot was executed. This value is
77 * stored in the corresponding index of the parent VCB's addrv.
79 * (4) mdb_vcb_find - Given an mdb_var_t, determines if there already exists a
80 * vcb for this variable, and if so returns it. This allows us to avoid
81 * re-creating a vcb every time through a walk, such as:
83 * > ::walk proc p | ::walk proc v | ::eval "<p=Kn"
85 * In this case, we don't want to create a new vcb for 'v' every time we execute
88 * Unfortunately, determining the addrv index is complicated by the fact that
89 * pipes involve the asynchronous execution of the dcmds and the parser. This
90 * asynchrony means that the parser may not actually consume the output of a
91 * given dcmd until long after it has completed, and thus when the parser is
92 * ready to reset dot, it does not know what addrv index produced this value.
93 * We work around this problem by explicitly flushing the pipeline after each
94 * dcmd invocation if VCBs are active. This does impact performance, so we
95 * may need to re-evaluate in the future if pipelines are producing huge
96 * amounts of data and a large number of VCBs are active simultaneously.
99 #include <mdb/mdb_frame.h>
100 #include <mdb/mdb_debug.h>
101 #include <mdb/mdb_modapi.h>
102 #include <mdb/mdb_vcb.h>
106 mdb_vcb_create(mdb_var_t
*v
)
108 mdb_vcb_t
*vcb
= mdb_zalloc(sizeof (mdb_vcb_t
), UM_SLEEP
);
114 mdb_vcb_destroy(mdb_vcb_t
*vcb
)
116 mdb_dprintf(MDB_DBG_DSTK
, "delete vcb %p (%s)\n", (void *)vcb
,
117 mdb_nv_get_name(vcb
->vc_var
));
119 mdb_addrvec_destroy(&vcb
->vc_addrv
);
120 mdb_free(vcb
, sizeof (mdb_vcb_t
));
124 mdb_vcb_propagate(mdb_vcb_t
*vcb
)
126 while (vcb
!= NULL
) {
127 mdb_addrvec_t
*adp
= &vcb
->vc_addrv
;
128 ASSERT(vcb
->vc_adnext
< adp
->ad_nelems
);
129 mdb_nv_set_value(vcb
->vc_var
, adp
->ad_data
[vcb
->vc_adnext
++]);
135 mdb_vcb_purge(mdb_vcb_t
*vcb
)
137 while (vcb
!= NULL
) {
138 mdb_vcb_t
*n
= vcb
->vc_link
;
139 mdb_vcb_destroy(vcb
);
145 mdb_vcb_inherit(mdb_cmd_t
*src
, mdb_cmd_t
*dst
)
147 mdb_vcb_t
*vc1
, *vc2
;
149 for (vc1
= src
->c_vcbs
; vc1
!= NULL
; vc1
= vc1
->vc_link
) {
150 vc2
= mdb_vcb_create(vc1
->vc_var
);
151 vc2
->vc_parent
= vc1
;
152 vc2
->vc_link
= dst
->c_vcbs
;
158 mdb_vcb_insert(mdb_vcb_t
*vcb
, mdb_frame_t
*fp
)
160 if (fp
->f_pcmd
!= NULL
) {
161 mdb_cmd_t
*cp
= fp
->f_pcmd
;
163 mdb_dprintf(MDB_DBG_DSTK
, "insert vcb %p (%s)\n",
164 (void *)vcb
, mdb_nv_get_name(vcb
->vc_var
));
166 ASSERT(vcb
->vc_link
== NULL
);
167 vcb
->vc_link
= cp
->c_vcbs
;
173 mdb_vcb_update(struct mdb_frame
*fp
, uintptr_t value
)
177 for (vcb
= fp
->f_pcmd
->c_vcbs
; vcb
!= NULL
; vcb
= vcb
->vc_link
) {
178 if (vcb
->vc_parent
!= NULL
) {
179 mdb_addrvec_t
*adp
= &vcb
->vc_parent
->vc_addrv
;
180 adp
->ad_ndx
= vcb
->vc_parent
->vc_adnext
- 1;
181 ASSERT(adp
->ad_ndx
< adp
->ad_nelems
);
182 value
= adp
->ad_data
[adp
->ad_ndx
++];
184 mdb_addrvec_unshift(&vcb
->vc_addrv
, value
);
189 mdb_vcb_find(mdb_var_t
*var
, mdb_frame_t
*fp
)
193 if (fp
->f_pcmd
!= NULL
) {
194 vcb
= fp
->f_pcmd
->c_vcbs
;
195 while (vcb
!= NULL
) {
196 if (vcb
->vc_var
== var
)