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