xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/combined.c (revision e13e346d8734036862432c746042cff8470e8ebd)
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 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <mdb/mdb_modapi.h>
29 
30 typedef struct combined_walk {
31 	int (*cw_init)(mdb_walk_state_t *);
32 	int (*cw_step)(mdb_walk_state_t *);
33 	void (*cw_fini)(mdb_walk_state_t *);
34 	struct combined_walk *cw_next;
35 	void *cw_data;
36 	boolean_t cw_initialized;
37 } combined_walk_t;
38 
39 typedef struct combined_walk_data {
40 	uintptr_t cwd_initial_walk_addr;	/* to init each walk */
41 	combined_walk_t *cwd_current_walk;
42 	combined_walk_t *cwd_final_walk;	/* tail pointer */
43 } combined_walk_data_t;
44 
45 /*
46  * Initialize a combined walk to
47  * A) present a single concatenated series of elements from different
48  *    structures, or
49  * B) select from several possible walks at runtime.
50  * Multiple walks are done in the same order passed to combined_walk_add(). Each
51  * walk is initialized with the same wsp->walk_addr.
52  */
53 void
54 combined_walk_init(mdb_walk_state_t *wsp)
55 {
56 	combined_walk_data_t *cwd;
57 
58 	cwd = mdb_alloc(sizeof (combined_walk_data_t), UM_SLEEP);
59 
60 	cwd->cwd_initial_walk_addr = wsp->walk_addr;
61 	cwd->cwd_current_walk = cwd->cwd_final_walk = NULL;
62 	wsp->walk_data = cwd;
63 }
64 
65 static void
66 combined_walk_append(combined_walk_data_t *cwd, combined_walk_t *cw)
67 {
68 	if (cwd->cwd_final_walk == NULL) {
69 		cwd->cwd_current_walk = cwd->cwd_final_walk = cw;
70 	} else {
71 		cwd->cwd_final_walk->cw_next = cw;
72 		cwd->cwd_final_walk = cw;
73 	}
74 }
75 
76 static combined_walk_t *
77 combined_walk_remove_current(combined_walk_data_t *cwd)
78 {
79 	combined_walk_t *cw = cwd->cwd_current_walk;
80 	if (cw == NULL) {
81 		return (NULL);
82 	}
83 	if (cw == cwd->cwd_final_walk) {
84 		cwd->cwd_final_walk = cw->cw_next;
85 	}
86 	cwd->cwd_current_walk = cw->cw_next;
87 	cw->cw_next = NULL;
88 	return (cw);
89 }
90 
91 void
92 combined_walk_add(mdb_walk_state_t *wsp,
93 	int (*walk_init)(mdb_walk_state_t *),
94 	int (*walk_step)(mdb_walk_state_t *),
95 	void (*walk_fini)(mdb_walk_state_t *))
96 {
97 	combined_walk_data_t *cwd = wsp->walk_data;
98 	combined_walk_t *cw;
99 
100 	cw = mdb_alloc(sizeof (combined_walk_t), UM_SLEEP);
101 
102 	cw->cw_init = walk_init;
103 	cw->cw_step = walk_step;
104 	cw->cw_fini = walk_fini;
105 	cw->cw_next = NULL;
106 	cw->cw_data = NULL;
107 	cw->cw_initialized = B_FALSE;
108 
109 	combined_walk_append(cwd, cw);
110 }
111 
112 int
113 combined_walk_step(mdb_walk_state_t *wsp)
114 {
115 	combined_walk_data_t *cwd = wsp->walk_data;
116 	combined_walk_t *cw = cwd->cwd_current_walk;
117 	int status;
118 
119 	if (cw == NULL) {
120 		return (WALK_DONE);
121 	}
122 
123 	if (cw->cw_initialized) {
124 		wsp->walk_data = cw->cw_data;
125 	} else {
126 		wsp->walk_addr = cwd->cwd_initial_walk_addr;
127 		status = cw->cw_init(wsp);
128 		cw->cw_data = wsp->walk_data;
129 		cw->cw_initialized = B_TRUE;
130 		if (status != WALK_NEXT) {
131 			wsp->walk_data = cwd;
132 			return (status);
133 		}
134 	}
135 
136 	status = cw->cw_step(wsp);
137 
138 	if (status == WALK_DONE) {
139 		(void) combined_walk_remove_current(cwd);
140 		cw->cw_fini(wsp);
141 		mdb_free(cw, sizeof (combined_walk_t));
142 		wsp->walk_data = cwd;
143 		return (combined_walk_step(wsp));
144 	}
145 
146 	wsp->walk_data = cwd;
147 	return (status);
148 }
149 
150 void
151 combined_walk_fini(mdb_walk_state_t *wsp)
152 {
153 	combined_walk_data_t *cwd = wsp->walk_data;
154 	combined_walk_t *cw;
155 
156 	while ((cw = combined_walk_remove_current(cwd)) != NULL) {
157 		if (cw->cw_initialized) {
158 			wsp->walk_data = cw->cw_data;
159 			cw->cw_fini(wsp);
160 		}
161 		mdb_free(cw, sizeof (combined_walk_t));
162 	}
163 
164 	mdb_free(cwd, sizeof (combined_walk_data_t));
165 }
166