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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
29 #include <mdb/mdb_modapi.h>
32 typedef struct list_walk_data
{
33 uintptr_t lw_head
; /* address of list head */
34 size_t lw_size
; /* size of list element */
35 size_t lw_offset
; /* list element linkage offset */
36 void *lw_obj
; /* buffer of lw_size to hold list element */
37 uintptr_t lw_end
; /* last node in specified range */
38 const char *lw_elem_name
;
39 int (*lw_elem_check
)(void *, uintptr_t, void *);
40 void *lw_elem_check_arg
;
44 * Initialize a forward walk through a list.
46 * begin and end optionally specify objects other than the first and last
47 * objects in the list; either or both may be NULL (defaulting to first and
50 * list_name and element_name specify command-specific labels other than
51 * "list_t" and "list element" for use in error messages.
53 * element_check() returns -1, 1, or 0: abort the walk with an error, stop
54 * without an error, or allow the normal callback; arg is an optional user
55 * argument to element_check().
58 list_walk_init_range(mdb_walk_state_t
*wsp
, uintptr_t begin
, uintptr_t end
,
59 const char *list_name
, const char *element_name
,
60 int (*element_check
)(void *, uintptr_t, void *), void *arg
)
62 list_walk_data_t
*lwd
;
65 if (list_name
== NULL
)
67 if (element_name
== NULL
)
68 element_name
= "list element";
70 if (mdb_vread(&list
, sizeof (list_t
), wsp
->walk_addr
) == -1) {
71 mdb_warn("failed to read %s at %#lx", list_name
,
76 if (list
.list_size
< list
.list_offset
+ sizeof (list_node_t
)) {
77 mdb_warn("invalid or uninitialized %s at %#lx\n", list_name
,
82 lwd
= mdb_alloc(sizeof (list_walk_data_t
), UM_SLEEP
);
84 lwd
->lw_size
= list
.list_size
;
85 lwd
->lw_offset
= list
.list_offset
;
86 lwd
->lw_obj
= mdb_alloc(list
.list_size
, UM_SLEEP
);
87 lwd
->lw_head
= (uintptr_t)&((list_t
*)wsp
->walk_addr
)->list_head
;
88 lwd
->lw_end
= (end
== (uintptr_t)NULL
?
89 (uintptr_t)NULL
: end
+ lwd
->lw_offset
);
90 lwd
->lw_elem_name
= element_name
;
91 lwd
->lw_elem_check
= element_check
;
92 lwd
->lw_elem_check_arg
= arg
;
94 wsp
->walk_addr
= (begin
== (uintptr_t)NULL
95 ? (uintptr_t)list
.list_head
.list_next
96 : begin
+ lwd
->lw_offset
);
103 list_walk_init(mdb_walk_state_t
*wsp
)
105 return (list_walk_init_range(wsp
, (uintptr_t)NULL
, (uintptr_t)NULL
,
106 NULL
, NULL
, NULL
, NULL
));
110 list_walk_init_named(mdb_walk_state_t
*wsp
,
111 const char *list_name
, const char *element_name
)
113 return (list_walk_init_range(wsp
, (uintptr_t)NULL
, (uintptr_t)NULL
,
114 list_name
, element_name
, NULL
, NULL
));
118 list_walk_init_checked(mdb_walk_state_t
*wsp
,
119 const char *list_name
, const char *element_name
,
120 int (*element_check
)(void *, uintptr_t, void *), void *arg
)
122 return (list_walk_init_range(wsp
, (uintptr_t)NULL
, (uintptr_t)NULL
,
123 list_name
, element_name
, element_check
, arg
));
127 list_walk_step(mdb_walk_state_t
*wsp
)
129 list_walk_data_t
*lwd
= wsp
->walk_data
;
130 uintptr_t addr
= wsp
->walk_addr
- lwd
->lw_offset
;
134 if (wsp
->walk_addr
== lwd
->lw_head
)
137 if (lwd
->lw_end
!= (uintptr_t)NULL
&& wsp
->walk_addr
== lwd
->lw_end
)
140 if (mdb_vread(lwd
->lw_obj
, lwd
->lw_size
, addr
) == -1) {
141 mdb_warn("failed to read %s at %#lx", lwd
->lw_elem_name
, addr
);
145 if (lwd
->lw_elem_check
!= NULL
) {
146 int rc
= lwd
->lw_elem_check(lwd
->lw_obj
, addr
,
147 lwd
->lw_elem_check_arg
);
154 status
= wsp
->walk_callback(addr
, lwd
->lw_obj
, wsp
->walk_cbdata
);
155 node
= (list_node_t
*)((uintptr_t)lwd
->lw_obj
+ lwd
->lw_offset
);
156 wsp
->walk_addr
= (uintptr_t)node
->list_next
;
162 list_walk_fini(mdb_walk_state_t
*wsp
)
164 list_walk_data_t
*lwd
= wsp
->walk_data
;
166 mdb_free(lwd
->lw_obj
, lwd
->lw_size
);
167 mdb_free(lwd
, sizeof (list_walk_data_t
));