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