1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2712 nn35248 * Common Development and Distribution License (the "License"). 6 2712 nn35248 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 6473 edp * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel /* 30 0 stevel * Proc Service API Interposition Layer 31 0 stevel * 32 0 stevel * In order to allow multiple MDB targets to make use of librtld_db, we 33 0 stevel * provide an interposition layer for functions in the proc_service.h API 34 0 stevel * that are used by librtld_db. Each of the functions used by librtld_db 35 0 stevel * can be conveniently expressed in terms of the MDB target API, so this 36 0 stevel * layer simply selects the appropriate target, invokes the corresponding 37 0 stevel * target API function, and then translates the error codes appropriately. 38 0 stevel * We expect that each proc_service entry point will be invoked with a 39 0 stevel * cookie (struct ps_prochandle *) which matches either a known MDB target, 40 0 stevel * or the value of a target's t->t_pshandle. This allows us to re-vector 41 0 stevel * calls to the proc service API around libproc (which also contains an 42 0 stevel * implementation of the proc_service API) like this: 43 0 stevel * 44 0 stevel * Linker map: 45 0 stevel * +---------+ +---------+ +------------+ Legend: 46 0 stevel * | MDB | ->| libproc | ->| librtld_db | <1> function in this file 47 0 stevel * +---------+ +---------+ +------------+ <2> function in libproc 48 0 stevel * ps_pread<1> ps_pread<2> call ps_pread() --+ 49 0 stevel * | 50 0 stevel * +---------------------------------------------+ 51 0 stevel * | 52 0 stevel * +-> ps_pread<1>(P, ...) 53 0 stevel * t = mdb_tgt_from_pshandle(P); 54 0 stevel * mdb_tgt_vread(t, ...); 55 0 stevel * 56 0 stevel * If we are debugging a user process, we then make these calls (which form 57 0 stevel * the equivalent of libproc's proc_service implementation): 58 0 stevel * 59 0 stevel * mdb_tgt_vread() -> proc target t->t_vread() -> libproc.so`Pread() 60 0 stevel * 61 0 stevel * If we are debugging a user process through a kernel crash dump (kproc 62 0 stevel * target), we make these calls: 63 0 stevel * 64 0 stevel * mdb_tgt_vread() -> kproc target t->t_vread() -> mdb_tgt_aread(kvm target) -> 65 0 stevel * kvm target t->t_aread() -> libkvm.so`kvm_aread() 66 0 stevel * 67 0 stevel * This design allows us to support both kproc's use of librtld_db, as well 68 0 stevel * as libproc's use of librtld_db, but it does lead to one unfortunate problem 69 0 stevel * in the creation of a proc target: when the proc target invokes libproc to 70 0 stevel * construct a ps_prochandle, and libproc in turn invokes librtld_db, MDB does 71 0 stevel * not yet know what ps_prochandle has been allocated inside of libproc since 72 0 stevel * this call has not yet returned. We also can't translate this ps_prochandle 73 0 stevel * to the target itself, since that target isn't ready to handle requests yet; 74 0 stevel * we actually need to pass the call back through to libproc. In order to 75 0 stevel * do that, we use libdl to lookup the address of libproc's definition of the 76 0 stevel * various functions (RTLD_NEXT on the link map chain) and store these in the 77 0 stevel * ps_ops structure below. If we ever fail to translate a ps_prochandle to 78 0 stevel * an MDB target, we simply pass the call through to libproc. 79 0 stevel */ 80 0 stevel 81 0 stevel #include <proc_service.h> 82 0 stevel #include <dlfcn.h> 83 0 stevel 84 0 stevel #include <mdb/mdb_target_impl.h> 85 0 stevel #include <mdb/mdb_debug.h> 86 0 stevel #include <mdb/mdb.h> 87 0 stevel 88 0 stevel static struct { 89 0 stevel ps_err_e (*ps_pread)(struct ps_prochandle *, 90 0 stevel psaddr_t, void *, size_t); 91 0 stevel ps_err_e (*ps_pwrite)(struct ps_prochandle *, 92 0 stevel psaddr_t, const void *, size_t); 93 0 stevel ps_err_e (*ps_pglobal_lookup)(struct ps_prochandle *, 94 0 stevel const char *, const char *, psaddr_t *); 95 0 stevel ps_err_e (*ps_pglobal_sym)(struct ps_prochandle *P, 96 0 stevel const char *, const char *, ps_sym_t *); 97 0 stevel ps_err_e (*ps_pauxv)(struct ps_prochandle *, 98 0 stevel const auxv_t **); 99 6473 edp ps_err_e (*ps_pbrandname)(struct ps_prochandle *, 100 6473 edp char *, size_t); 101 0 stevel ps_err_e (*ps_pdmodel)(struct ps_prochandle *, 102 0 stevel int *); 103 0 stevel } ps_ops; 104 0 stevel 105 0 stevel static mdb_tgt_t * 106 0 stevel mdb_tgt_from_pshandle(void *P) 107 0 stevel { 108 0 stevel mdb_tgt_t *t; 109 0 stevel 110 0 stevel for (t = mdb_list_next(&mdb.m_tgtlist); t; t = mdb_list_next(t)) { 111 0 stevel if (t == P || t->t_pshandle == P) 112 0 stevel return (t); 113 0 stevel } 114 0 stevel 115 0 stevel return (NULL); 116 0 stevel } 117 0 stevel 118 0 stevel /* 119 0 stevel * Read from the specified target virtual address. 120 0 stevel */ 121 0 stevel ps_err_e 122 0 stevel ps_pread(struct ps_prochandle *P, psaddr_t addr, void *buf, size_t size) 123 0 stevel { 124 0 stevel mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 125 0 stevel 126 0 stevel if (t == NULL) 127 0 stevel return (ps_ops.ps_pread(P, addr, buf, size)); 128 0 stevel 129 0 stevel if (mdb_tgt_vread(t, buf, size, addr) != size) 130 0 stevel return (PS_BADADDR); 131 0 stevel 132 0 stevel return (PS_OK); 133 0 stevel } 134 0 stevel 135 0 stevel /* 136 0 stevel * Write to the specified target virtual address. 137 0 stevel */ 138 0 stevel ps_err_e 139 0 stevel ps_pwrite(struct ps_prochandle *P, psaddr_t addr, const void *buf, size_t size) 140 0 stevel { 141 0 stevel mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 142 0 stevel 143 0 stevel if (t == NULL) 144 0 stevel return (ps_ops.ps_pwrite(P, addr, buf, size)); 145 0 stevel 146 0 stevel if (mdb_tgt_vwrite(t, buf, size, addr) != size) 147 0 stevel return (PS_BADADDR); 148 0 stevel 149 0 stevel return (PS_OK); 150 0 stevel } 151 0 stevel 152 0 stevel /* 153 0 stevel * Search for a symbol by name and return the corresponding address. 154 0 stevel */ 155 0 stevel ps_err_e 156 0 stevel ps_pglobal_lookup(struct ps_prochandle *P, const char *object, 157 0 stevel const char *name, psaddr_t *symp) 158 0 stevel { 159 0 stevel mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 160 0 stevel GElf_Sym sym; 161 0 stevel 162 0 stevel if (t == NULL) 163 0 stevel return (ps_ops.ps_pglobal_lookup(P, object, name, symp)); 164 0 stevel 165 0 stevel if (mdb_tgt_lookup_by_name(t, object, name, &sym, NULL) == 0) { 166 0 stevel *symp = (psaddr_t)sym.st_value; 167 0 stevel return (PS_OK); 168 0 stevel } 169 0 stevel 170 0 stevel return (PS_NOSYM); 171 0 stevel } 172 0 stevel 173 0 stevel /* 174 0 stevel * Search for a symbol by name and return the corresponding symbol data. 175 0 stevel * If we're compiled _LP64, we just call mdb_tgt_lookup_by_name and return 176 0 stevel * because ps_sym_t is defined to be an Elf64_Sym, which is the same as a 177 0 stevel * GElf_Sym. In the _ILP32 case, we have to convert mdb_tgt_lookup_by_name's 178 0 stevel * result back to a ps_sym_t (which is an Elf32_Sym). 179 0 stevel */ 180 0 stevel ps_err_e 181 0 stevel ps_pglobal_sym(struct ps_prochandle *P, const char *object, 182 0 stevel const char *name, ps_sym_t *symp) 183 0 stevel { 184 0 stevel mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 185 0 stevel #if defined(_ILP32) 186 0 stevel GElf_Sym sym; 187 0 stevel 188 0 stevel if (t == NULL) 189 0 stevel return (ps_ops.ps_pglobal_sym(P, object, name, symp)); 190 0 stevel 191 0 stevel if (mdb_tgt_lookup_by_name(t, object, name, &sym, NULL) == 0) { 192 0 stevel symp->st_name = (Elf32_Word)sym.st_name; 193 0 stevel symp->st_value = (Elf32_Addr)sym.st_value; 194 0 stevel symp->st_size = (Elf32_Word)sym.st_size; 195 0 stevel symp->st_info = ELF32_ST_INFO( 196 0 stevel GELF_ST_BIND(sym.st_info), GELF_ST_TYPE(sym.st_info)); 197 0 stevel symp->st_other = sym.st_other; 198 0 stevel symp->st_shndx = sym.st_shndx; 199 0 stevel return (PS_OK); 200 0 stevel } 201 0 stevel 202 0 stevel #elif defined(_LP64) 203 0 stevel if (t == NULL) 204 0 stevel return (ps_ops.ps_pglobal_sym(P, object, name, symp)); 205 0 stevel 206 0 stevel if (mdb_tgt_lookup_by_name(t, object, name, symp, NULL) == 0) 207 0 stevel return (PS_OK); 208 0 stevel #endif 209 0 stevel 210 0 stevel return (PS_NOSYM); 211 0 stevel } 212 0 stevel 213 0 stevel /* 214 0 stevel * Report a debug message. We allow proc_service API clients to report 215 0 stevel * messages via our debug stream if the MDB_DBG_PSVC token is enabled. 216 0 stevel */ 217 0 stevel void 218 0 stevel ps_plog(const char *format, ...) 219 0 stevel { 220 0 stevel va_list alist; 221 0 stevel 222 0 stevel va_start(alist, format); 223 0 stevel mdb_dvprintf(MDB_DBG_PSVC, format, alist); 224 0 stevel va_end(alist); 225 0 stevel } 226 0 stevel 227 0 stevel /* 228 0 stevel * Return the auxv structure from the process being examined. 229 0 stevel */ 230 0 stevel ps_err_e 231 0 stevel ps_pauxv(struct ps_prochandle *P, const auxv_t **auxvp) 232 0 stevel { 233 0 stevel mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 234 0 stevel 235 0 stevel if (t == NULL) 236 0 stevel return (ps_ops.ps_pauxv(P, auxvp)); 237 0 stevel 238 2712 nn35248 if (mdb_tgt_auxv(t, auxvp) != 0) 239 2712 nn35248 return (PS_ERR); 240 0 stevel 241 0 stevel return (PS_OK); 242 0 stevel } 243 0 stevel 244 6473 edp ps_err_e 245 6473 edp ps_pbrandname(struct ps_prochandle *P, char *buf, size_t len) 246 6473 edp { 247 6473 edp mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 248 6473 edp const auxv_t *auxv; 249 6473 edp 250 6473 edp if (t == NULL) 251 6473 edp return (ps_ops.ps_pbrandname(P, buf, len)); 252 6473 edp 253 6473 edp if (mdb_tgt_auxv(t, &auxv) != 0) 254 6473 edp return (PS_ERR); 255 6473 edp 256 6473 edp while (auxv->a_type != AT_NULL) { 257 6473 edp if (auxv->a_type == AT_SUN_BRANDNAME) 258 6473 edp break; 259 6473 edp auxv++; 260 6473 edp } 261 6473 edp if (auxv->a_type == AT_NULL) 262 6473 edp return (PS_ERR); 263 6473 edp 264 6473 edp if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT, 265 6473 edp buf, len, auxv->a_un.a_val) <= 0) 266 6473 edp return (PS_ERR); 267 6473 edp 268 6473 edp return (PS_OK); 269 6473 edp } 270 6473 edp 271 0 stevel /* 272 0 stevel * Return the data model of the target. 273 0 stevel */ 274 0 stevel ps_err_e 275 0 stevel ps_pdmodel(struct ps_prochandle *P, int *dm) 276 0 stevel { 277 0 stevel mdb_tgt_t *t = mdb_tgt_from_pshandle(P); 278 0 stevel 279 0 stevel if (t == NULL) 280 0 stevel return (ps_ops.ps_pdmodel(P, dm)); 281 0 stevel 282 0 stevel switch (mdb_tgt_dmodel(t)) { 283 0 stevel case MDB_TGT_MODEL_LP64: 284 0 stevel *dm = PR_MODEL_LP64; 285 0 stevel return (PS_OK); 286 0 stevel case MDB_TGT_MODEL_ILP32: 287 0 stevel *dm = PR_MODEL_ILP32; 288 0 stevel return (PS_OK); 289 0 stevel } 290 0 stevel 291 0 stevel return (PS_ERR); 292 0 stevel } 293 0 stevel 294 0 stevel /* 295 0 stevel * Stub function in case we cannot find the necessary symbols from libproc. 296 0 stevel */ 297 0 stevel static ps_err_e 298 0 stevel ps_fail(struct ps_prochandle *P) 299 0 stevel { 300 0 stevel mdb_dprintf(MDB_DBG_PSVC, "failing call to pshandle %p\n", (void *)P); 301 0 stevel return (PS_BADPID); 302 0 stevel } 303 0 stevel 304 0 stevel /* 305 0 stevel * Initialization function for the proc service interposition layer: we use 306 0 stevel * libdl to look up the next definition of each function in the link map. 307 0 stevel */ 308 0 stevel void 309 0 stevel mdb_pservice_init(void) 310 0 stevel { 311 0 stevel if ((ps_ops.ps_pread = (ps_err_e (*)()) 312 0 stevel dlsym(RTLD_NEXT, "ps_pread")) == NULL) 313 0 stevel ps_ops.ps_pread = (ps_err_e (*)())ps_fail; 314 0 stevel 315 0 stevel if ((ps_ops.ps_pwrite = (ps_err_e (*)()) 316 0 stevel dlsym(RTLD_NEXT, "ps_pwrite")) == NULL) 317 0 stevel ps_ops.ps_pwrite = (ps_err_e (*)())ps_fail; 318 0 stevel 319 0 stevel if ((ps_ops.ps_pglobal_lookup = (ps_err_e (*)()) 320 0 stevel dlsym(RTLD_NEXT, "ps_pglobal_lookup")) == NULL) 321 0 stevel ps_ops.ps_pglobal_lookup = (ps_err_e (*)())ps_fail; 322 0 stevel 323 0 stevel if ((ps_ops.ps_pglobal_sym = (ps_err_e (*)()) 324 0 stevel dlsym(RTLD_NEXT, "ps_pglobal_sym")) == NULL) 325 0 stevel ps_ops.ps_pglobal_sym = (ps_err_e (*)())ps_fail; 326 0 stevel 327 0 stevel if ((ps_ops.ps_pauxv = (ps_err_e (*)()) 328 0 stevel dlsym(RTLD_NEXT, "ps_pauxv")) == NULL) 329 0 stevel ps_ops.ps_pauxv = (ps_err_e (*)())ps_fail; 330 0 stevel 331 6473 edp if ((ps_ops.ps_pbrandname = (ps_err_e (*)()) 332 6473 edp dlsym(RTLD_NEXT, "ps_pbrandname")) == NULL) 333 6473 edp ps_ops.ps_pbrandname = (ps_err_e (*)())ps_fail; 334 6473 edp 335 0 stevel if ((ps_ops.ps_pdmodel = (ps_err_e (*)()) 336 0 stevel dlsym(RTLD_NEXT, "ps_pdmodel")) == NULL) 337 0 stevel ps_ops.ps_pdmodel = (ps_err_e (*)())ps_fail; 338 0 stevel } 339