#include <proc_service.h>
#include <dlfcn.h>
#include <mdb/mdb_target_impl.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb.h>
static struct {
ps_err_e (*ps_pread)(struct ps_prochandle *,
psaddr_t, void *, size_t);
ps_err_e (*ps_pwrite)(struct ps_prochandle *,
psaddr_t, const void *, size_t);
ps_err_e (*ps_pglobal_lookup)(struct ps_prochandle *,
const char *, const char *, psaddr_t *);
ps_err_e (*ps_pglobal_sym)(struct ps_prochandle *P,
const char *, const char *, ps_sym_t *);
ps_err_e (*ps_pauxv)(struct ps_prochandle *,
const auxv_t **);
ps_err_e (*ps_pbrandname)(struct ps_prochandle *,
char *, size_t);
ps_err_e (*ps_pdmodel)(struct ps_prochandle *,
int *);
} ps_ops;
static mdb_tgt_t *
mdb_tgt_from_pshandle(void *P)
{
mdb_tgt_t *t;
for (t = mdb_list_next(&mdb.m_tgtlist); t; t = mdb_list_next(t)) {
if (t == P || t->t_pshandle == P)
return (t);
}
return (NULL);
}
ps_err_e
ps_pread(struct ps_prochandle *P, psaddr_t addr, void *buf, size_t size)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
if (t == NULL)
return (ps_ops.ps_pread(P, addr, buf, size));
if (mdb_tgt_vread(t, buf, size, addr) != size)
return (PS_BADADDR);
return (PS_OK);
}
ps_err_e
ps_pwrite(struct ps_prochandle *P, psaddr_t addr, const void *buf, size_t size)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
if (t == NULL)
return (ps_ops.ps_pwrite(P, addr, buf, size));
if (mdb_tgt_vwrite(t, buf, size, addr) != size)
return (PS_BADADDR);
return (PS_OK);
}
ps_err_e
ps_pglobal_lookup(struct ps_prochandle *P, const char *object,
const char *name, psaddr_t *symp)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
GElf_Sym sym;
if (t == NULL)
return (ps_ops.ps_pglobal_lookup(P, object, name, symp));
if (mdb_tgt_lookup_by_name(t, object, name, &sym, NULL) == 0) {
*symp = (psaddr_t)sym.st_value;
return (PS_OK);
}
return (PS_NOSYM);
}
ps_err_e
ps_pglobal_sym(struct ps_prochandle *P, const char *object,
const char *name, ps_sym_t *symp)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
#if defined(_ILP32)
GElf_Sym sym;
if (t == NULL)
return (ps_ops.ps_pglobal_sym(P, object, name, symp));
if (mdb_tgt_lookup_by_name(t, object, name, &sym, NULL) == 0) {
symp->st_name = (Elf32_Word)sym.st_name;
symp->st_value = (Elf32_Addr)sym.st_value;
symp->st_size = (Elf32_Word)sym.st_size;
symp->st_info = ELF32_ST_INFO(
GELF_ST_BIND(sym.st_info), GELF_ST_TYPE(sym.st_info));
symp->st_other = sym.st_other;
symp->st_shndx = sym.st_shndx;
return (PS_OK);
}
#elif defined(_LP64)
if (t == NULL)
return (ps_ops.ps_pglobal_sym(P, object, name, symp));
if (mdb_tgt_lookup_by_name(t, object, name, symp, NULL) == 0)
return (PS_OK);
#endif
return (PS_NOSYM);
}
void
ps_plog(const char *format, ...)
{
va_list alist;
va_start(alist, format);
mdb_dvprintf(MDB_DBG_PSVC, format, alist);
va_end(alist);
}
ps_err_e
ps_pauxv(struct ps_prochandle *P, const auxv_t **auxvp)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
if (t == NULL)
return (ps_ops.ps_pauxv(P, auxvp));
if (mdb_tgt_auxv(t, auxvp) != 0)
return (PS_ERR);
return (PS_OK);
}
ps_err_e
ps_pbrandname(struct ps_prochandle *P, char *buf, size_t len)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
const auxv_t *auxv;
if (t == NULL)
return (ps_ops.ps_pbrandname(P, buf, len));
if (mdb_tgt_auxv(t, &auxv) != 0)
return (PS_ERR);
while (auxv->a_type != AT_NULL) {
if (auxv->a_type == AT_SUN_BRANDNAME)
break;
auxv++;
}
if (auxv->a_type == AT_NULL)
return (PS_ERR);
if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT,
buf, len, auxv->a_un.a_val) <= 0)
return (PS_ERR);
return (PS_OK);
}
ps_err_e
ps_pdmodel(struct ps_prochandle *P, int *dm)
{
mdb_tgt_t *t = mdb_tgt_from_pshandle(P);
if (t == NULL)
return (ps_ops.ps_pdmodel(P, dm));
switch (mdb_tgt_dmodel(t)) {
case MDB_TGT_MODEL_LP64:
*dm = PR_MODEL_LP64;
return (PS_OK);
case MDB_TGT_MODEL_ILP32:
*dm = PR_MODEL_ILP32;
return (PS_OK);
}
return (PS_ERR);
}
static ps_err_e
ps_fail(struct ps_prochandle *P)
{
mdb_dprintf(MDB_DBG_PSVC, "failing call to pshandle %p\n", (void *)P);
return (PS_BADPID);
}
void
mdb_pservice_init(void)
{
if ((ps_ops.ps_pread = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pread")) == NULL)
ps_ops.ps_pread = (ps_err_e (*)())ps_fail;
if ((ps_ops.ps_pwrite = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pwrite")) == NULL)
ps_ops.ps_pwrite = (ps_err_e (*)())ps_fail;
if ((ps_ops.ps_pglobal_lookup = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pglobal_lookup")) == NULL)
ps_ops.ps_pglobal_lookup = (ps_err_e (*)())ps_fail;
if ((ps_ops.ps_pglobal_sym = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pglobal_sym")) == NULL)
ps_ops.ps_pglobal_sym = (ps_err_e (*)())ps_fail;
if ((ps_ops.ps_pauxv = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pauxv")) == NULL)
ps_ops.ps_pauxv = (ps_err_e (*)())ps_fail;
if ((ps_ops.ps_pbrandname = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pbrandname")) == NULL)
ps_ops.ps_pbrandname = (ps_err_e (*)())ps_fail;
if ((ps_ops.ps_pdmodel = (ps_err_e (*)())
dlsym(RTLD_NEXT, "ps_pdmodel")) == NULL)
ps_ops.ps_pdmodel = (ps_err_e (*)())ps_fail;
}