Walker Definitions

A walker is composed of three functions, init, step, and fini, which are defined according to
the example prototypes above. A walker is invoked by the debugger when one
of the walk functions (such as mdb_walk()) is called, or
when the user executes the ::walk built-in dcmd. When the
walk begins, MDB calls the walker's init function, passing it the address
of a new mdb_walk_state_t structure, as defined in <sys/mdb_modapi.h>:

A separate mdb_walk_state_t is created
for each walk, so that multiple instances of the same walker can be active
simultaneously. The state structure contains the callback the walker should
invoke at each step (walk_callback), and the private
data for the callback (walk_cbdata), as specified
to mdb_walk(), for example. The walk_cbdata pointer
is opaque to the walker: it must not modify or dereference this value, nor
can it assume it is a pointer to valid memory.

The starting address for the walk is stored in walk_addr.
This is either NULL if mdb_walk() was called, or the address
parameter specified to mdb_pwalk(). If the ::walk built-in
was used, walk_addr will be non-NULL if an explicit
address was specified on the left-hand side of ::walk.
A walk with a starting address of NULL is referred to as global.
A walk with an explicit non-NULL starting address is referred to as local.

The walk_data and walk_arg fields
are provided for use as private storage for the walker. Complex walkers might
need to allocate an auxiliary state structure and set walk_data to
point to this structure. Each time a walk is initiated, walk_arg is
initialized to the value of the walk_init_arg member of
the corresponding walker's mdb_walker_t structure.

In some cases, it is useful to have several walkers share the same init,
step, and fini routines. For example, the MDB genunix module
provides walkers for each kernel memory cache. These share the same init,
step, and fini functions, and use the walk_init_arg member
of the mdb_walker_t to specify the address of the appropriate
cache as the walk_arg.

If the walker calls mdb_layered_walk() to instantiate
an underlying layer, then the underlying layer will reset walk_addr and walk_layer prior to each call to the walker's step function.
The underlying layer sets walk_addr to the target
virtual address of the underlying object, and set walk_layer to
point to the walker's local copy of the underlying object. For more information
on layered walks, refer to the discussion of mdb_layered_walk() below.

The walker init and step functions are expected to return one of the
following status values:

WALK_NEXT

Proceed to the next step. When the walk init function returns WALK_NEXT, MDB invokes the walk step function. When the walk step
function returns WALK_NEXT, this indicates that MDB should
call the step function again.

WALK_DONE

The walk has completed successfully. WALK_DONE can
be returned by either the step function to indicate that the walk is complete,
or by the init function to indicate that no steps are needed (for example,
if the given data structure is empty).

WALK_ERR

The walk has terminated due to an error. If WALK_ERR is
returned by the init function, mdb_walk() (or any of its
counterparts) returns –1 to indicate that the walker failed to initialize.
If WALK_ERR is returned by the step function, the walk
terminates but mdb_walk() returns success.

The walk_callback is also expected to return
one of the values above. Therefore, the walk step function's job is to determine
the address of the next object, read in a local copy of this object, call
the walk_callback function, then return its status.
The step function can also return WALK_DONE or WALK_ERR without invoking the callback if the walk is complete or if an
error occurred.

The walker itself is defined using the mdb_walker_t structure,
defined in :

The walk_name and walk_descr fields should be initialized
to point to strings containing the name and a brief description of the walker,
respectively. A walker is required to have a non-NULL name and description,
and the name cannot contain any of the MDB meta-characters. The description
string is printed by the ::walkers and ::dmods built-in
dcmds.

The walk_init, walk_step, and walk_fini members refer to the walk functions themselves, as described
earlier. The walk_init and walk_fini members
can be set to NULL to indicate that no special initialization or cleanup actions
need to be taken. The walk_step member cannot be set to
NULL. The walk_init_arg member is used to initialize the walk_arg member of each new mdb_walk_state_t created
for the given walker, as described earlier. Figure 10–1 shows a flowchart for the algorithm of a typical walker.

Figure 10–1 Sample Walker

The walker is designed to iterate over the list of proc_t structures
in the kernel. The head of the list is stored in the global practive variable,
and each element's p_next pointer points to the next proc_t in the list. The list is terminated with a NULL pointer.
In the walker's init routine, the practive symbol
is located using mdb_lookup_by_name() step (1), and its
value is copied into the mdb_walk_state_t pointed
to by wsp.

In the walker's step function, the next proc_t structure
in the list is copied into the debugger's address space using mdb_vread() step (2), the callback function is invoked with a pointer to this
local copy, step (3), and then the mdb_walk_state_t is
updated with the address of the proc_t structure
for the next iteration. This update corresponds to following the pointer,
step (4), to the next element in the list.

These steps demonstrate the structure of a typical walker: the init
routine locates the global information for a particular data structure, the
step function reads in a local copy of the next data item and passes it to
the callback function, and the address of the next element is read. Finally,
when the walk terminates, the fini function frees any private storage.