#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
#include "ctxop.h"
struct ctxop_walk_state {
uintptr_t cws_head;
uint_t cws_next_offset;
};
int
ctxop_walk_init(mdb_walk_state_t *wsp)
{
struct ctxop_walk_state *priv;
int offset;
uintptr_t addr;
if (wsp->walk_addr == 0) {
mdb_warn("must specify thread for ctxop walk\n");
return (WALK_ERR);
}
offset = mdb_ctf_offsetof_by_name("kthread_t", "t_ctx");
if (offset == -1)
return (WALK_ERR);
if (mdb_vread(&addr, sizeof (addr),
wsp->walk_addr + offset) != sizeof (addr)) {
mdb_warn("failed to read thread %p", wsp->walk_addr);
return (WALK_ERR);
}
if (addr == 0) {
wsp->walk_data = NULL;
return (WALK_DONE);
}
offset = mdb_ctf_offsetof_by_name("struct ctxop", "next");
if (offset == -1)
return (WALK_ERR);
priv = mdb_alloc(sizeof (*priv), UM_SLEEP);
priv->cws_head = addr;
priv->cws_next_offset = (uint_t)offset;
wsp->walk_data = priv;
wsp->walk_addr = addr;
return (WALK_NEXT);
}
int
ctxop_walk_step(mdb_walk_state_t *wsp)
{
struct ctxop_walk_state *priv = wsp->walk_data;
uintptr_t next;
int status;
if (mdb_vread(&next, sizeof (next),
wsp->walk_addr + priv->cws_next_offset) == -1) {
mdb_warn("failed to read ctxop`next at %p",
wsp->walk_addr + priv->cws_next_offset);
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
if (status == WALK_NEXT) {
if (next == 0 || next == priv->cws_head) {
status = WALK_DONE;
}
}
wsp->walk_addr = next;
return (status);
}
void
ctxop_walk_fini(mdb_walk_state_t *wsp)
{
struct ctxop_walk_state *priv = wsp->walk_data;
if (priv != NULL) {
mdb_free(priv, sizeof (*priv));
}
}