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 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <fcntl.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <sys/types.h> 33 #include <sys/signal.h> 34 #include <sys/fault.h> 35 #include <sys/syscall.h> 36 #include <procfs.h> 37 #include <sys/auxv.h> 38 #include <libelf.h> 39 #include <sys/stat.h> 40 #include <sys/mman.h> 41 #include <link.h> 42 #include <sys/param.h> 43 #include <sys/machelf.h> 44 #include <stdarg.h> 45 46 #include "rdb.h" 47 48 static char * 49 conv_lmid(Lmid_t ident, char *buf, size_t len) 50 { 51 if (len < 17) 52 return (NULL); 53 if (ident == LM_ID_BASE) 54 return (strncpy(buf, " BASE ", len)); 55 56 if (ident == LM_ID_LDSO) 57 return (strncpy(buf, " LDSO ", len)); 58 59 (void) sprintf(buf, "0x%llx", (unsigned long long)ident); 60 return (buf); 61 } 62 63 map_info_t * 64 str_to_map(struct ps_prochandle *ph, const char *soname) 65 { 66 map_info_t *mip; 67 68 if (soname == PS_OBJ_LDSO) 69 mip = (map_info_t *)&(ph->pp_ldsomap); 70 else if (soname == PS_OBJ_EXEC) 71 mip = (map_info_t *)&(ph->pp_execmap); 72 else { 73 for (mip = ph->pp_lmaplist.ml_head; mip; mip = mip->mi_next) 74 if (strcmp(soname, mip->mi_name) == 0) 75 break; 76 } 77 return (mip); 78 } 79 80 map_info_t * 81 addr_to_map(struct ps_prochandle *ph, ulong_t addr) 82 { 83 map_info_t *mip; 84 if (ph->pp_lmaplist.ml_head == NULL) { 85 /* 86 * To early to have the full Link Map info available 87 * so we use the initial info obtained from procfs 88 */ 89 if ((addr >= ph->pp_ldsomap.mi_addr) && 90 (addr <= ph->pp_ldsomap.mi_end)) 91 return ((map_info_t *)&(ph->pp_ldsomap)); 92 93 if ((addr >= ph->pp_execmap.mi_addr) && 94 (addr <= ph->pp_execmap.mi_end)) 95 return ((map_info_t *)&(ph->pp_execmap)); 96 97 return (NULL); 98 } 99 100 for (mip = ph->pp_lmaplist.ml_head; mip; mip = mip->mi_next) 101 if ((addr >= mip->mi_addr) && 102 (addr <= mip->mi_end)) 103 return (mip); 104 105 return (NULL); 106 } 107 108 retc_t 109 display_linkmaps(struct ps_prochandle *ph) 110 { 111 char flagstr[1024]; 112 map_info_t *mip; 113 114 if (ph->pp_lmaplist.ml_head == NULL) { 115 (void) printf("link-maps not yet available\n"); 116 return (RET_FAILED); 117 } 118 (void) printf("Link Maps\n"); 119 (void) printf("---------\n"); 120 for (mip = ph->pp_lmaplist.ml_head; mip; mip = mip->mi_next) { 121 char sbuf[32]; 122 rd_loadobj_t *lp = &mip->mi_loadobj; 123 (void) printf("link-map: id: %s name: ", 124 conv_lmid(lp->rl_lmident, sbuf, 32)); 125 if (mip->mi_refname) 126 (void) printf("%s(%s)\n", mip->mi_name, 127 mip->mi_refname); 128 else 129 (void) printf("%s\n", mip->mi_name); 130 131 (void) printf(" base: 0x%08lx padd_base: 0x%08lx\n", 132 lp->rl_base, lp->rl_padstart); 133 (void) printf(" data_base: 0x%08llx\n", 134 (unsigned long long)lp->rl_data_base); 135 (void) printf(" end: 0x%08lx padd_end: 0x%08lx\n", 136 lp->rl_bend, lp->rl_padend); 137 flagstr[0] = '\0'; 138 139 if (lp->rl_flags & RD_FLG_MEM_OBJECT) { 140 (void) strcat(flagstr, " MEMOBJECT"); 141 } 142 (void) printf(" dynamic: 0x%08lx flags: " 143 "0x%08x:[%s ]\n", lp->rl_dynamic, lp->rl_flags, flagstr); 144 } 145 146 return (RET_OK); 147 } 148 149 retc_t 150 display_maps(struct ps_prochandle *ph) 151 { 152 struct stat stbuf; 153 void *ptr; 154 prmap_t *mapptr; 155 156 if (fstat(ph->pp_mapfd, &stbuf) == -1) 157 perr("stat map"); 158 159 ptr = malloc(stbuf.st_size); 160 if (pread(ph->pp_mapfd, ptr, stbuf.st_size, 0) == -1) 161 perr("dm: reading map"); 162 163 (void) puts("\nMappings"); 164 (void) puts("--------"); 165 if (ph->pp_dmodel == PR_MODEL_LP64) 166 (void) puts("addr size prot ident name"); 167 else 168 (void) puts("addr size prot ident name"); 169 170 for (mapptr = (prmap_t *)ptr; 171 (uintptr_t)mapptr < ((uintptr_t)ptr + stbuf.st_size); 172 mapptr++) { 173 map_info_t *mip; 174 175 if (ph->pp_dmodel == PR_MODEL_LP64) 176 (void) printf("%#18llx %#08llx %#04x", 177 EC_ADDR(mapptr->pr_vaddr), EC_OFF(mapptr->pr_size), 178 mapptr->pr_mflags); 179 else 180 (void) printf("0x%08llx 0x%06llx 0x%02x", 181 EC_ADDR(mapptr->pr_vaddr), EC_OFF(mapptr->pr_size), 182 mapptr->pr_mflags); 183 184 if ((mip = addr_to_map(ph, 185 (ulong_t)(mapptr->pr_vaddr))) != NULL) { 186 if (mip->mi_refname) { 187 (void) printf(" 0x%02lx %s(%s)", 188 mip->mi_lmident, mip->mi_name, 189 mip->mi_refname); 190 } else 191 (void) printf(" 0x%02lx %s", mip->mi_lmident, 192 mip->mi_name); 193 } 194 (void) putchar('\n'); 195 } 196 (void) putchar('\n'); 197 198 free(ptr); 199 return (RET_OK); 200 } 201 202 retc_t 203 load_map(struct ps_prochandle *procp, caddr_t baddr, map_info_t *mp) 204 { 205 Elf *elf; 206 GElf_Ehdr ehdr; 207 GElf_Phdr phdr; 208 Elf_Scn *scn = NULL; 209 int cnt; 210 prmap_t *mapptr; 211 void *ptr; 212 struct stat stbuf; 213 int filefd = -1; 214 215 if (fstat(procp->pp_mapfd, &stbuf) == -1) 216 perr("stat map"); 217 218 ptr = malloc(stbuf.st_size); 219 if (pread(procp->pp_mapfd, ptr, stbuf.st_size, 0) == -1) 220 perr("dm: reading map"); 221 222 for (mapptr = (prmap_t *)ptr; 223 (uintptr_t)mapptr < ((uintptr_t)ptr + stbuf.st_size); 224 mapptr++) { 225 226 if ((mapptr->pr_vaddr <= (uintptr_t)baddr) && 227 ((mapptr->pr_vaddr + mapptr->pr_size) > 228 (uintptr_t)baddr)) { 229 if (mapptr->pr_mapname[0]) { 230 char procname[MAXPATHLEN]; 231 232 (void) snprintf(procname, MAXPATHLEN - 1, 233 "/proc/%d/object/%s", procp->pp_pid, 234 mapptr->pr_mapname); 235 filefd = open(procname, O_RDONLY); 236 } 237 break; 238 } 239 } 240 free(ptr); 241 242 if (filefd == -1) { 243 (void) fprintf(stderr, "unable to find file association to " 244 "mapping address 0x%08llx\n", EC_NATPTR(baddr)); 245 return (RET_FAILED); 246 } 247 248 if ((elf = elf_begin(filefd, ELF_C_READ, 0)) == NULL) { 249 (void) fprintf(stderr, "elf_begin(): %s\n", elf_errmsg(-1)); 250 return (RET_FAILED); 251 } 252 253 if (elf_kind(elf) != ELF_K_ELF) { 254 (void) printf("non-elf file\n"); 255 (void) elf_end(elf); 256 return (RET_FAILED); 257 } 258 259 mp->mi_elf = elf; 260 mp->mi_flags = 0; 261 mp->mi_mapfd = filefd; 262 263 if (gelf_getehdr(mp->mi_elf, &ehdr) == NULL) { 264 (void) printf("gelf_getehdr(): %s\n", elf_errmsg(-1)); 265 (void) elf_end(mp->mi_elf); 266 return (RET_FAILED); 267 } 268 mp->mi_ehdr = ehdr; 269 if (ehdr.e_type == ET_EXEC) 270 mp->mi_flags |= FLG_MI_EXEC; 271 272 mp->mi_end = 0; 273 #if defined(_ELF64) 274 mp->mi_addr = (ulong_t)0xffffffffffffffff; 275 #else 276 mp->mi_addr = (ulong_t)0xffffffff; 277 #endif 278 for (cnt = 0; cnt < (int)(ehdr.e_phnum); cnt++) { 279 if (gelf_getphdr(mp->mi_elf, cnt, &phdr) == NULL) { 280 (void) printf("gelf_getphdr(): %s\n", elf_errmsg(-1)); 281 (void) elf_end(mp->mi_elf); 282 return (RET_FAILED); 283 } 284 285 if (phdr.p_type == PT_LOAD) { 286 if (mp->mi_end < (ulong_t)(phdr.p_vaddr + 287 phdr.p_memsz)) 288 mp->mi_end = (ulong_t)(phdr.p_vaddr + 289 phdr.p_memsz); 290 if (mp->mi_addr > phdr.p_vaddr) 291 mp->mi_addr = phdr.p_vaddr; 292 } 293 } 294 295 mp->mi_pltbase = 0; 296 mp->mi_pltsize = 0; 297 mp->mi_pltentsz = 0; 298 mp->mi_dynsym.st_symn = 0; 299 while ((scn = elf_nextscn(mp->mi_elf, scn)) != NULL) { 300 GElf_Shdr shdr; 301 Elf_Data *dp; 302 Elf_Scn *tscn = NULL; 303 304 if (gelf_getshdr(scn, &shdr) == NULL) { 305 (void) printf("gelf_getshdr(): %s\n", elf_errmsg(-1)); 306 (void) elf_end(mp->mi_elf); 307 return (RET_FAILED); 308 } 309 310 switch (shdr.sh_type) { 311 case SHT_DYNSYM: 312 dp = elf_getdata(scn, 0); 313 mp->mi_dynsym.st_syms_pri = dp; 314 tscn = elf_getscn(mp->mi_elf, shdr.sh_link); 315 mp->mi_dynsym.st_symn += 316 shdr.sh_size / shdr.sh_entsize; 317 dp = elf_getdata(tscn, 0); 318 mp->mi_dynsym.st_strs = (char *)dp->d_buf; 319 break; 320 case SHT_SUNW_LDYNSYM: 321 dp = elf_getdata(scn, 0); 322 mp->mi_dynsym.st_syms_aux = dp; 323 mp->mi_dynsym.st_symn_aux = 324 shdr.sh_size / shdr.sh_entsize; 325 mp->mi_dynsym.st_symn += mp->mi_dynsym.st_symn_aux; 326 break; 327 case SHT_SYMTAB: 328 dp = elf_getdata(scn, 0); 329 mp->mi_symtab.st_syms_pri = dp; 330 tscn = elf_getscn(mp->mi_elf, shdr.sh_link); 331 mp->mi_symtab.st_symn = 332 shdr.sh_size / shdr.sh_entsize; 333 dp = elf_getdata(tscn, 0); 334 mp->mi_symtab.st_strs = (char *)dp->d_buf; 335 break; 336 case PLTSECTT: 337 if (strcmp(PLTSECT, elf_strptr(mp->mi_elf, 338 ehdr.e_shstrndx, shdr.sh_name)) == 0) { 339 mp->mi_pltbase = shdr.sh_addr; 340 mp->mi_pltsize = shdr.sh_size; 341 mp->mi_pltentsz = shdr.sh_entsize; 342 } 343 break; 344 default: 345 /* nothing */ 346 break; 347 } 348 } 349 return (RET_OK); 350 } 351 352 static int 353 map_iter(const rd_loadobj_t *lop, void *cd) 354 { 355 struct ps_prochandle *ph = (struct ps_prochandle *)cd; 356 map_info_t *mip; 357 char buf[MAXPATHLEN]; 358 359 if ((mip = (map_info_t *)calloc(1, sizeof (map_info_t))) == NULL) { 360 (void) fprintf(stderr, "map_iter: memory error: allocation " 361 "failed\n"); 362 return (0); 363 } 364 365 mip->mi_loadobj = *lop; 366 367 if (proc_string_read(ph, lop->rl_nameaddr, 368 buf, MAXPATHLEN) == RET_FAILED) { 369 (void) fprintf(stderr, "mi: bad object name address " 370 "passed: 0x%lx\n", lop->rl_nameaddr); 371 free(mip); 372 return (0); 373 } 374 mip->mi_name = strdup(buf); 375 376 377 if (lop->rl_refnameaddr) { 378 if (proc_string_read(ph, lop->rl_refnameaddr, buf, 379 MAXPATHLEN) == RET_FAILED) { 380 (void) fprintf(stderr, "mi1: bad object name address " 381 "passed: 0x%lx\n", lop->rl_refnameaddr); 382 free(mip); 383 return (0); 384 } 385 mip->mi_refname = strdup(buf); 386 } else 387 mip->mi_refname = NULL; 388 389 /* 390 * Relocatable objects are processed to create in-memory shared objects, 391 * and as such have no file associated with the allocated memory shared 392 * object. 393 */ 394 if ((lop->rl_flags & RD_FLG_MEM_OBJECT) == 0) 395 (void) load_map(ph, (caddr_t)lop->rl_base, mip); 396 if ((mip->mi_flags & FLG_MI_EXEC) == 0) { 397 mip->mi_end += lop->rl_base; 398 mip->mi_addr += lop->rl_base; 399 } 400 mip->mi_lmident = lop->rl_lmident; 401 mip->mi_next = NULL; 402 403 if (ph->pp_lmaplist.ml_head == NULL) { 404 ph->pp_lmaplist.ml_head = ph->pp_lmaplist.ml_tail = mip; 405 return (1); 406 } 407 408 ph->pp_lmaplist.ml_tail->mi_next = mip; 409 ph->pp_lmaplist.ml_tail = mip; 410 411 return (1); 412 } 413 414 void 415 free_linkmaps(struct ps_prochandle *ph) 416 { 417 map_info_t *cur, *prev; 418 419 for (cur = ph->pp_lmaplist.ml_head, prev = NULL; cur; 420 prev = cur, cur = cur->mi_next) { 421 if (prev) { 422 (void) elf_end(prev->mi_elf); 423 (void) close(prev->mi_mapfd); 424 free(prev->mi_name); 425 if (prev->mi_refname) 426 free(prev->mi_refname); 427 free(prev); 428 } 429 } 430 if (prev) { 431 (void) elf_end(prev->mi_elf); 432 (void) close(prev->mi_mapfd); 433 free(prev->mi_name); 434 if (prev->mi_refname) 435 free(prev->mi_refname); 436 free(prev); 437 } 438 ph->pp_lmaplist.ml_head = ph->pp_lmaplist.ml_tail = NULL; 439 } 440 441 retc_t 442 get_linkmaps(struct ps_prochandle *ph) 443 { 444 free_linkmaps(ph); 445 (void) rd_loadobj_iter(ph->pp_rap, map_iter, ph); 446 return (RET_OK); 447 } 448 449 retc_t 450 set_objpad(struct ps_prochandle *ph, size_t padsize) 451 { 452 if (rd_objpad_enable(ph->pp_rap, padsize) != RD_OK) { 453 (void) printf("rdb: error setting object padding\n"); 454 return (RET_FAILED); 455 } 456 return (RET_OK); 457 } 458