xref: /titanic_52/usr/src/cmd/dis/dis_list.c (revision dc0093f44ee4fac928e006850f8ed53f68277af5)
1*dc0093f4Seschrock /*
2*dc0093f4Seschrock  * CDDL HEADER START
3*dc0093f4Seschrock  *
4*dc0093f4Seschrock  * The contents of this file are subject to the terms of the
5*dc0093f4Seschrock  * Common Development and Distribution License (the "License").
6*dc0093f4Seschrock  * You may not use this file except in compliance with the License.
7*dc0093f4Seschrock  *
8*dc0093f4Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*dc0093f4Seschrock  * or http://www.opensolaris.org/os/licensing.
10*dc0093f4Seschrock  * See the License for the specific language governing permissions
11*dc0093f4Seschrock  * and limitations under the License.
12*dc0093f4Seschrock  *
13*dc0093f4Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
14*dc0093f4Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*dc0093f4Seschrock  * If applicable, add the following below this CDDL HEADER, with the
16*dc0093f4Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
17*dc0093f4Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
18*dc0093f4Seschrock  *
19*dc0093f4Seschrock  * CDDL HEADER END
20*dc0093f4Seschrock  */
21*dc0093f4Seschrock 
22*dc0093f4Seschrock /*
23*dc0093f4Seschrock  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*dc0093f4Seschrock  * Use is subject to license terms.
25*dc0093f4Seschrock  */
26*dc0093f4Seschrock 
27*dc0093f4Seschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*dc0093f4Seschrock 
29*dc0093f4Seschrock #include <stddef.h>
30*dc0093f4Seschrock #include <stdlib.h>
31*dc0093f4Seschrock #include <string.h>
32*dc0093f4Seschrock 
33*dc0093f4Seschrock #include "dis_target.h"
34*dc0093f4Seschrock #include "dis_list.h"
35*dc0093f4Seschrock #include "dis_util.h"
36*dc0093f4Seschrock 
37*dc0093f4Seschrock /*
38*dc0093f4Seschrock  * List support functions.
39*dc0093f4Seschrock  *
40*dc0093f4Seschrock  * Support routines for managing lists of sections and functions.  We first
41*dc0093f4Seschrock  * process the command line arguments into lists of strings.  For each target,
42*dc0093f4Seschrock  * we resolve these strings against the set of available sections and/or
43*dc0093f4Seschrock  * functions to arrive at the set of objects to disassemble.
44*dc0093f4Seschrock  *
45*dc0093f4Seschrock  * We export two types of lists, namelists and resolvelists.  The first is used
46*dc0093f4Seschrock  * to record names given as command line options.  The latter is used to
47*dc0093f4Seschrock  * maintain the data objects specific to a given target.
48*dc0093f4Seschrock  */
49*dc0093f4Seschrock 
50*dc0093f4Seschrock typedef struct unresolved_name {
51*dc0093f4Seschrock 	const char	*un_name;	/* name of function or object */
52*dc0093f4Seschrock 	int		un_value;	/* user-supplied data */
53*dc0093f4Seschrock 	int		un_mark;	/* internal counter */
54*dc0093f4Seschrock 	uu_list_node_t	un_node;	/* uulist node */
55*dc0093f4Seschrock } unresolved_name_t;
56*dc0093f4Seschrock 
57*dc0093f4Seschrock typedef struct resolved_name {
58*dc0093f4Seschrock 	void		*rn_data;	/* section or function data */
59*dc0093f4Seschrock 	int		rn_value;	/* user-supplied data */
60*dc0093f4Seschrock 	uu_list_node_t	rn_node;	/* uulist node */
61*dc0093f4Seschrock } resolved_name_t;
62*dc0093f4Seschrock 
63*dc0093f4Seschrock static uu_list_pool_t *unresolved_pool;
64*dc0093f4Seschrock static uu_list_pool_t *resolved_pool;
65*dc0093f4Seschrock static int current_mark = 0;
66*dc0093f4Seschrock 
67*dc0093f4Seschrock static void
68*dc0093f4Seschrock initialize_pools(void)
69*dc0093f4Seschrock {
70*dc0093f4Seschrock 	unresolved_pool = uu_list_pool_create(
71*dc0093f4Seschrock 	    "unresolved_pool", sizeof (unresolved_name_t),
72*dc0093f4Seschrock 	    offsetof(unresolved_name_t, un_node), NULL, 0);
73*dc0093f4Seschrock 	resolved_pool = uu_list_pool_create(
74*dc0093f4Seschrock 	    "resolved_pool", sizeof (resolved_name_t),
75*dc0093f4Seschrock 	    offsetof(resolved_name_t, rn_node), NULL, 0);
76*dc0093f4Seschrock 
77*dc0093f4Seschrock 	if (unresolved_pool == NULL ||
78*dc0093f4Seschrock 	    resolved_pool == NULL)
79*dc0093f4Seschrock 		die("out of memory");
80*dc0093f4Seschrock }
81*dc0093f4Seschrock 
82*dc0093f4Seschrock /*
83*dc0093f4Seschrock  * Returns an empty list of unresolved names.
84*dc0093f4Seschrock  */
85*dc0093f4Seschrock dis_namelist_t *
86*dc0093f4Seschrock dis_namelist_create(void)
87*dc0093f4Seschrock {
88*dc0093f4Seschrock 	uu_list_t *listp;
89*dc0093f4Seschrock 
90*dc0093f4Seschrock 	/*
91*dc0093f4Seschrock 	 * If this is the first request to create a list, initialize the list
92*dc0093f4Seschrock 	 * pools.
93*dc0093f4Seschrock 	 */
94*dc0093f4Seschrock 	if (unresolved_pool == NULL)
95*dc0093f4Seschrock 		initialize_pools();
96*dc0093f4Seschrock 
97*dc0093f4Seschrock 	if ((listp = uu_list_create(unresolved_pool, NULL, 0)) == NULL)
98*dc0093f4Seschrock 		die("out of memory");
99*dc0093f4Seschrock 
100*dc0093f4Seschrock 	return (listp);
101*dc0093f4Seschrock }
102*dc0093f4Seschrock 
103*dc0093f4Seschrock /*
104*dc0093f4Seschrock  * Adds the given name to the unresolved list.  'value' is an arbitrary value
105*dc0093f4Seschrock  * which is preserved for this entry, even when resolved against a target.  This
106*dc0093f4Seschrock  * allows the caller to associate similar behavior (such as the difference
107*dc0093f4Seschrock  * between -d, -D, and -s) without having to create multiple lists.
108*dc0093f4Seschrock  */
109*dc0093f4Seschrock void
110*dc0093f4Seschrock dis_namelist_add(dis_namelist_t *list, const char *name, int value)
111*dc0093f4Seschrock {
112*dc0093f4Seschrock 	unresolved_name_t *node;
113*dc0093f4Seschrock 
114*dc0093f4Seschrock 	node = safe_malloc(sizeof (unresolved_name_t));
115*dc0093f4Seschrock 
116*dc0093f4Seschrock 	node->un_name = name;
117*dc0093f4Seschrock 	node->un_value = value;
118*dc0093f4Seschrock 	node->un_mark = 0;
119*dc0093f4Seschrock 
120*dc0093f4Seschrock 	(void) uu_list_insert_before(list, NULL, node);
121*dc0093f4Seschrock }
122*dc0093f4Seschrock 
123*dc0093f4Seschrock /*
124*dc0093f4Seschrock  * Internal callback structure used
125*dc0093f4Seschrock  */
126*dc0093f4Seschrock typedef struct cb_data {
127*dc0093f4Seschrock 	int		cb_mark;
128*dc0093f4Seschrock 	uu_list_t	*cb_source;
129*dc0093f4Seschrock 	uu_list_t	*cb_resolved;
130*dc0093f4Seschrock } cb_data_t;
131*dc0093f4Seschrock 
132*dc0093f4Seschrock /*
133*dc0093f4Seschrock  * For each section, walk the list of unresolved names and resolve those that
134*dc0093f4Seschrock  * correspond to real functions.  We mark functions as we see them, and re-walk
135*dc0093f4Seschrock  * the list a second time to warn about functions we didn't find.
136*dc0093f4Seschrock  *
137*dc0093f4Seschrock  * This is an O(n * m) algorithm, but we typically search for only a single
138*dc0093f4Seschrock  * function.
139*dc0093f4Seschrock  */
140*dc0093f4Seschrock /* ARGSUSED */
141*dc0093f4Seschrock static void
142*dc0093f4Seschrock walk_sections(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
143*dc0093f4Seschrock {
144*dc0093f4Seschrock 	cb_data_t *cb = data;
145*dc0093f4Seschrock 	unresolved_name_t *unp;
146*dc0093f4Seschrock 	uu_list_walk_t *walk;
147*dc0093f4Seschrock 
148*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(cb->cb_source, UU_DEFAULT)) == NULL)
149*dc0093f4Seschrock 		die("out of memory");
150*dc0093f4Seschrock 
151*dc0093f4Seschrock 	while ((unp = uu_list_walk_next(walk)) != NULL) {
152*dc0093f4Seschrock 		if (strcmp(unp->un_name, dis_section_name(scn)) == 0) {
153*dc0093f4Seschrock 			resolved_name_t *resolved;
154*dc0093f4Seschrock 
155*dc0093f4Seschrock 			/*
156*dc0093f4Seschrock 			 * Mark the current node as seen
157*dc0093f4Seschrock 			 */
158*dc0093f4Seschrock 			unp->un_mark = cb->cb_mark;
159*dc0093f4Seschrock 
160*dc0093f4Seschrock 			/*
161*dc0093f4Seschrock 			 * Add the data to the resolved list
162*dc0093f4Seschrock 			 */
163*dc0093f4Seschrock 			resolved = safe_malloc(sizeof (resolved_name_t));
164*dc0093f4Seschrock 
165*dc0093f4Seschrock 			resolved->rn_data = dis_section_copy(scn);
166*dc0093f4Seschrock 			resolved->rn_value = unp->un_value;
167*dc0093f4Seschrock 
168*dc0093f4Seschrock 			(void) uu_list_insert_before(cb->cb_resolved, NULL,
169*dc0093f4Seschrock 			    resolved);
170*dc0093f4Seschrock 		}
171*dc0093f4Seschrock 	}
172*dc0093f4Seschrock 
173*dc0093f4Seschrock 	uu_list_walk_end(walk);
174*dc0093f4Seschrock }
175*dc0093f4Seschrock 
176*dc0093f4Seschrock /*
177*dc0093f4Seschrock  * Take a list of unresolved names and create a resolved list of sections.  We
178*dc0093f4Seschrock  * rely on walk_sections() to do the dirty work.  After resolving the sections,
179*dc0093f4Seschrock  * we check for any unmarked names and warn the user about missing sections.
180*dc0093f4Seschrock  */
181*dc0093f4Seschrock dis_scnlist_t *
182*dc0093f4Seschrock dis_namelist_resolve_sections(dis_namelist_t *namelist, dis_tgt_t *tgt)
183*dc0093f4Seschrock {
184*dc0093f4Seschrock 	uu_list_t *listp;
185*dc0093f4Seschrock 	cb_data_t cb;
186*dc0093f4Seschrock 	unresolved_name_t *unp;
187*dc0093f4Seschrock 	uu_list_walk_t *walk;
188*dc0093f4Seschrock 
189*dc0093f4Seschrock 	/*
190*dc0093f4Seschrock 	 * Walk all sections in the target, calling walk_sections() for each
191*dc0093f4Seschrock 	 * one.
192*dc0093f4Seschrock 	 */
193*dc0093f4Seschrock 	if ((listp = uu_list_create(resolved_pool, NULL, UU_DEFAULT)) == NULL)
194*dc0093f4Seschrock 		die("out of memory");
195*dc0093f4Seschrock 
196*dc0093f4Seschrock 	cb.cb_mark = ++current_mark;
197*dc0093f4Seschrock 	cb.cb_source = namelist;
198*dc0093f4Seschrock 	cb.cb_resolved = listp;
199*dc0093f4Seschrock 
200*dc0093f4Seschrock 	dis_tgt_section_iter(tgt, walk_sections, &cb);
201*dc0093f4Seschrock 
202*dc0093f4Seschrock 	/*
203*dc0093f4Seschrock 	 * Walk all elements of the unresolved list, and report any that we
204*dc0093f4Seschrock 	 * didn't mark in the process.
205*dc0093f4Seschrock 	 */
206*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(namelist, UU_DEFAULT)) == NULL)
207*dc0093f4Seschrock 		die("out of memory");
208*dc0093f4Seschrock 
209*dc0093f4Seschrock 	while ((unp = uu_list_walk_next(walk)) != NULL) {
210*dc0093f4Seschrock 		if (unp->un_mark != current_mark)
211*dc0093f4Seschrock 			warn("failed to find section '%s' in '%s'",
212*dc0093f4Seschrock 			    unp->un_name, dis_tgt_name(tgt));
213*dc0093f4Seschrock 	}
214*dc0093f4Seschrock 
215*dc0093f4Seschrock 	uu_list_walk_end(walk);
216*dc0093f4Seschrock 
217*dc0093f4Seschrock 	return (listp);
218*dc0093f4Seschrock }
219*dc0093f4Seschrock 
220*dc0093f4Seschrock /*
221*dc0093f4Seschrock  * Similar to walk_sections(), but for functions.
222*dc0093f4Seschrock  */
223*dc0093f4Seschrock /* ARGSUSED */
224*dc0093f4Seschrock static void
225*dc0093f4Seschrock walk_functions(dis_tgt_t *tgt, dis_func_t *func, void *data)
226*dc0093f4Seschrock {
227*dc0093f4Seschrock 	cb_data_t *cb = data;
228*dc0093f4Seschrock 	unresolved_name_t *unp;
229*dc0093f4Seschrock 	uu_list_walk_t *walk;
230*dc0093f4Seschrock 
231*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(cb->cb_source, UU_DEFAULT)) == NULL)
232*dc0093f4Seschrock 		die("out of memory");
233*dc0093f4Seschrock 
234*dc0093f4Seschrock 	while ((unp = uu_list_walk_next(walk)) != NULL) {
235*dc0093f4Seschrock 		if (strcmp(unp->un_name, dis_function_name(func)) == 0) {
236*dc0093f4Seschrock 			resolved_name_t *resolved;
237*dc0093f4Seschrock 
238*dc0093f4Seschrock 			unp->un_mark = cb->cb_mark;
239*dc0093f4Seschrock 
240*dc0093f4Seschrock 			resolved = safe_malloc(sizeof (resolved_name_t));
241*dc0093f4Seschrock 
242*dc0093f4Seschrock 			resolved->rn_data = dis_function_copy(func);
243*dc0093f4Seschrock 			resolved->rn_value = unp->un_value;
244*dc0093f4Seschrock 
245*dc0093f4Seschrock 			(void) uu_list_insert_before(cb->cb_resolved, NULL,
246*dc0093f4Seschrock 			    resolved);
247*dc0093f4Seschrock 		}
248*dc0093f4Seschrock 	}
249*dc0093f4Seschrock 
250*dc0093f4Seschrock 	uu_list_walk_end(walk);
251*dc0093f4Seschrock }
252*dc0093f4Seschrock 
253*dc0093f4Seschrock /*
254*dc0093f4Seschrock  * Take a list of unresolved names and create a resolved list of functions.  We
255*dc0093f4Seschrock  * rely on walk_functions() to do the dirty work.  After resolving the
256*dc0093f4Seschrock  * functions, * we check for any unmarked names and warn the user about missing
257*dc0093f4Seschrock  * functions.
258*dc0093f4Seschrock  */
259*dc0093f4Seschrock dis_funclist_t *
260*dc0093f4Seschrock dis_namelist_resolve_functions(dis_namelist_t *namelist, dis_tgt_t *tgt)
261*dc0093f4Seschrock {
262*dc0093f4Seschrock 	uu_list_t *listp;
263*dc0093f4Seschrock 	uu_list_walk_t *walk;
264*dc0093f4Seschrock 	unresolved_name_t *unp;
265*dc0093f4Seschrock 	cb_data_t cb;
266*dc0093f4Seschrock 
267*dc0093f4Seschrock 	if ((listp = uu_list_create(resolved_pool, NULL, UU_DEFAULT)) == NULL)
268*dc0093f4Seschrock 		die("out of memory");
269*dc0093f4Seschrock 
270*dc0093f4Seschrock 	cb.cb_mark = ++current_mark;
271*dc0093f4Seschrock 	cb.cb_source = namelist;
272*dc0093f4Seschrock 	cb.cb_resolved = listp;
273*dc0093f4Seschrock 
274*dc0093f4Seschrock 	dis_tgt_function_iter(tgt, walk_functions, &cb);
275*dc0093f4Seschrock 
276*dc0093f4Seschrock 	/*
277*dc0093f4Seschrock 	 * Walk unresolved list and report any missing functions.
278*dc0093f4Seschrock 	 */
279*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(namelist, UU_DEFAULT)) == NULL)
280*dc0093f4Seschrock 		die("out of memory");
281*dc0093f4Seschrock 
282*dc0093f4Seschrock 	while ((unp = uu_list_walk_next(walk)) != NULL) {
283*dc0093f4Seschrock 		if (unp->un_mark != current_mark)
284*dc0093f4Seschrock 			warn("failed to find function '%s' in '%s'",
285*dc0093f4Seschrock 			    unp->un_name, dis_tgt_name(tgt));
286*dc0093f4Seschrock 	}
287*dc0093f4Seschrock 
288*dc0093f4Seschrock 	uu_list_walk_end(walk);
289*dc0093f4Seschrock 
290*dc0093f4Seschrock 	return (listp);
291*dc0093f4Seschrock }
292*dc0093f4Seschrock 
293*dc0093f4Seschrock /*
294*dc0093f4Seschrock  * Returns true if the given list is empty.
295*dc0093f4Seschrock  */
296*dc0093f4Seschrock int
297*dc0093f4Seschrock dis_namelist_empty(dis_namelist_t *list)
298*dc0093f4Seschrock {
299*dc0093f4Seschrock 	return (uu_list_numnodes(list) == 0);
300*dc0093f4Seschrock }
301*dc0093f4Seschrock 
302*dc0093f4Seschrock static void
303*dc0093f4Seschrock free_list(uu_list_t *list)
304*dc0093f4Seschrock {
305*dc0093f4Seschrock 	uu_list_walk_t *walk;
306*dc0093f4Seschrock 	void *data;
307*dc0093f4Seschrock 
308*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(list, UU_WALK_ROBUST)) == NULL)
309*dc0093f4Seschrock 		die("out of memory");
310*dc0093f4Seschrock 
311*dc0093f4Seschrock 	while ((data = uu_list_walk_next(walk)) != NULL) {
312*dc0093f4Seschrock 		uu_list_remove(list, data);
313*dc0093f4Seschrock 		free(data);
314*dc0093f4Seschrock 	}
315*dc0093f4Seschrock 
316*dc0093f4Seschrock 	uu_list_walk_end(walk);
317*dc0093f4Seschrock 
318*dc0093f4Seschrock 	uu_list_destroy(list);
319*dc0093f4Seschrock }
320*dc0093f4Seschrock 
321*dc0093f4Seschrock /*
322*dc0093f4Seschrock  * Destroy a list of sections.  First, walk the list and free the associated
323*dc0093f4Seschrock  * section data.  Pass the list onto to free_list() to clean up the rest of the
324*dc0093f4Seschrock  * list.
325*dc0093f4Seschrock  */
326*dc0093f4Seschrock void
327*dc0093f4Seschrock dis_scnlist_destroy(dis_scnlist_t *list)
328*dc0093f4Seschrock {
329*dc0093f4Seschrock 	uu_list_walk_t *walk;
330*dc0093f4Seschrock 	resolved_name_t *data;
331*dc0093f4Seschrock 
332*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
333*dc0093f4Seschrock 		die("out of memory");
334*dc0093f4Seschrock 
335*dc0093f4Seschrock 	while ((data = uu_list_walk_next(walk)) != NULL)
336*dc0093f4Seschrock 		dis_section_free(data->rn_data);
337*dc0093f4Seschrock 
338*dc0093f4Seschrock 	uu_list_walk_end(walk);
339*dc0093f4Seschrock 
340*dc0093f4Seschrock 	free_list(list);
341*dc0093f4Seschrock }
342*dc0093f4Seschrock 
343*dc0093f4Seschrock /*
344*dc0093f4Seschrock  * Destroy a list of functions.  First, walk the list and free the associated
345*dc0093f4Seschrock  * function data.  Pass the list onto to free_list() to clean up the rest of the
346*dc0093f4Seschrock  * list.
347*dc0093f4Seschrock  */
348*dc0093f4Seschrock void
349*dc0093f4Seschrock dis_funclist_destroy(dis_funclist_t *list)
350*dc0093f4Seschrock {
351*dc0093f4Seschrock 	uu_list_walk_t *walk;
352*dc0093f4Seschrock 	resolved_name_t *data;
353*dc0093f4Seschrock 
354*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
355*dc0093f4Seschrock 		die("out of memory");
356*dc0093f4Seschrock 
357*dc0093f4Seschrock 	while ((data = uu_list_walk_next(walk)) != NULL)
358*dc0093f4Seschrock 		dis_function_free(data->rn_data);
359*dc0093f4Seschrock 
360*dc0093f4Seschrock 	uu_list_walk_end(walk);
361*dc0093f4Seschrock 
362*dc0093f4Seschrock 	free_list(list);
363*dc0093f4Seschrock }
364*dc0093f4Seschrock 
365*dc0093f4Seschrock /*
366*dc0093f4Seschrock  * Destroy a lis tof unresolved names.
367*dc0093f4Seschrock  */
368*dc0093f4Seschrock void
369*dc0093f4Seschrock dis_namelist_destroy(dis_namelist_t *list)
370*dc0093f4Seschrock {
371*dc0093f4Seschrock 	free_list(list);
372*dc0093f4Seschrock }
373*dc0093f4Seschrock 
374*dc0093f4Seschrock /*
375*dc0093f4Seschrock  * Iterate over a resolved list of sections.
376*dc0093f4Seschrock  */
377*dc0093f4Seschrock void
378*dc0093f4Seschrock dis_scnlist_iter(uu_list_t *list, void (*func)(dis_scn_t *, int, void *),
379*dc0093f4Seschrock     void *arg)
380*dc0093f4Seschrock {
381*dc0093f4Seschrock 	uu_list_walk_t *walk;
382*dc0093f4Seschrock 	resolved_name_t *data;
383*dc0093f4Seschrock 
384*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
385*dc0093f4Seschrock 		die("out of memory");
386*dc0093f4Seschrock 
387*dc0093f4Seschrock 	while ((data = uu_list_walk_next(walk)) != NULL)
388*dc0093f4Seschrock 		func(data->rn_data, data->rn_value, arg);
389*dc0093f4Seschrock 
390*dc0093f4Seschrock 	uu_list_walk_end(walk);
391*dc0093f4Seschrock }
392*dc0093f4Seschrock 
393*dc0093f4Seschrock /*
394*dc0093f4Seschrock  * Iterate over a resolved list of functions.
395*dc0093f4Seschrock  */
396*dc0093f4Seschrock void
397*dc0093f4Seschrock dis_funclist_iter(uu_list_t *list, void (*func)(dis_func_t *, int, void *),
398*dc0093f4Seschrock     void *arg)
399*dc0093f4Seschrock {
400*dc0093f4Seschrock 	uu_list_walk_t *walk;
401*dc0093f4Seschrock 	resolved_name_t *data;
402*dc0093f4Seschrock 
403*dc0093f4Seschrock 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
404*dc0093f4Seschrock 		die("out of memory");
405*dc0093f4Seschrock 
406*dc0093f4Seschrock 	while ((data = uu_list_walk_next(walk)) != NULL)
407*dc0093f4Seschrock 		func(data->rn_data, data->rn_value, arg);
408*dc0093f4Seschrock 
409*dc0093f4Seschrock 	uu_list_walk_end(walk);
410*dc0093f4Seschrock }
411