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