Home | History | Annotate | Download | only in common
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <unistd.h>
     30 #include <fcntl.h>
     31 #include <string.h>
     32 #include <errno.h>
     33 #include <sys/types.h>
     34 #include <sys/signal.h>
     35 #include <sys/fault.h>
     36 #include <sys/syscall.h>
     37 #include <procfs.h>
     38 #include <sys/auxv.h>
     39 #include <libelf.h>
     40 #include <sys/stat.h>
     41 #include <sys/mman.h>
     42 #include <link.h>
     43 #include <sys/param.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("%#18lx %#08lx %#04x", mapptr->pr_vaddr,
    177 			    mapptr->pr_size, mapptr->pr_mflags);
    178 		else
    179 			(void) printf("0x%08lx 0x%06lx 0x%02x",
    180 			    mapptr->pr_vaddr, mapptr->pr_size,
    181 			    mapptr->pr_mflags);
    182 
    183 		if ((mip = addr_to_map(ph,
    184 		    (ulong_t)(mapptr->pr_vaddr))) != NULL) {
    185 			if (mip->mi_refname) {
    186 				(void) printf(" 0x%02lx  %s(%s)",
    187 				    mip->mi_lmident, mip->mi_name,
    188 				    mip->mi_refname);
    189 			} else
    190 				(void) printf(" 0x%02lx  %s", mip->mi_lmident,
    191 				    mip->mi_name);
    192 		}
    193 		(void) putchar('\n');
    194 	}
    195 	(void) putchar('\n');
    196 
    197 	free(ptr);
    198 	return (RET_OK);
    199 }
    200 
    201 retc_t
    202 load_map(struct ps_prochandle *procp, caddr_t baddr, map_info_t *mp)
    203 {
    204 	Elf 		*elf;
    205 	GElf_Ehdr 	ehdr;
    206 	GElf_Phdr	phdr;
    207 	Elf_Scn 	*scn = NULL;
    208 	int		cnt;
    209 	prmap_t 	*mapptr;
    210 	void 		*ptr;
    211 	struct stat	stbuf;
    212 	int		filefd = -1;
    213 
    214 	if (fstat(procp->pp_mapfd, &stbuf) == -1)
    215 		perr("stat map");
    216 
    217 	ptr = malloc(stbuf.st_size);
    218 	if (pread(procp->pp_mapfd, ptr, stbuf.st_size, 0) == -1)
    219 		perr("dm: reading map");
    220 
    221 	for (mapptr = (prmap_t *)ptr;
    222 	    (uintptr_t)mapptr < ((uintptr_t)ptr + stbuf.st_size);
    223 	    mapptr++) {
    224 
    225 		if ((mapptr->pr_vaddr <= (uintptr_t)baddr) &&
    226 		    ((mapptr->pr_vaddr + mapptr->pr_size) >
    227 		    (uintptr_t)baddr)) {
    228 			if (mapptr->pr_mapname[0]) {
    229 				char	procname[MAXPATHLEN];
    230 
    231 				(void) snprintf(procname, MAXPATHLEN - 1,
    232 				    "/proc/%d/object/%s", procp->pp_pid,
    233 				    mapptr->pr_mapname);
    234 				filefd = open(procname, O_RDONLY);
    235 			}
    236 			break;
    237 		}
    238 	}
    239 	free(ptr);
    240 
    241 	if (filefd == -1) {
    242 		(void) fprintf(stderr, "unable to find file association to "
    243 		    "maping address 0x%08lx\n", baddr);
    244 		return (RET_FAILED);
    245 	}
    246 
    247 	if ((elf = elf_begin(filefd, ELF_C_READ, 0)) == NULL) {
    248 		(void) fprintf(stderr, "elf_begin(): %s\n", elf_errmsg(-1));
    249 		return (RET_FAILED);
    250 	}
    251 
    252 	if (elf_kind(elf) != ELF_K_ELF) {
    253 		(void) printf("non-elf file\n");
    254 		(void) elf_end(elf);
    255 		return (RET_FAILED);
    256 	}
    257 
    258 	mp->mi_elf = elf;
    259 	mp->mi_flags = 0;
    260 	mp->mi_mapfd = filefd;
    261 
    262 	if (gelf_getehdr(mp->mi_elf, &ehdr) == NULL) {
    263 		(void) printf("gelf_getehdr(): %s\n", elf_errmsg(-1));
    264 		(void) elf_end(mp->mi_elf);
    265 		return (RET_FAILED);
    266 	}
    267 	mp->mi_ehdr = ehdr;
    268 	if (ehdr.e_type == ET_EXEC)
    269 		mp->mi_flags |= FLG_MI_EXEC;
    270 
    271 	mp->mi_end = 0;
    272 #if	defined(_ELF64)
    273 	mp->mi_addr = (ulong_t)0xffffffffffffffff;
    274 #else
    275 	mp->mi_addr = (ulong_t)0xffffffff;
    276 #endif
    277 	for (cnt = 0; cnt < (int)(ehdr.e_phnum); cnt++) {
    278 		if (gelf_getphdr(mp->mi_elf, cnt, &phdr) == NULL) {
    279 			(void) printf("gelf_getphdr(): %s\n", elf_errmsg(-1));
    280 			(void) elf_end(mp->mi_elf);
    281 			return (RET_FAILED);
    282 		}
    283 
    284 		if (phdr.p_type == PT_LOAD) {
    285 			if (mp->mi_end < (ulong_t)(phdr.p_vaddr +
    286 			    phdr.p_memsz))
    287 				mp->mi_end = (ulong_t)(phdr.p_vaddr +
    288 				    phdr.p_memsz);
    289 			if (mp->mi_addr > phdr.p_vaddr)
    290 				mp->mi_addr = phdr.p_vaddr;
    291 		}
    292 	}
    293 
    294 	mp->mi_pltbase = 0;
    295 	mp->mi_pltsize = 0;
    296 	mp->mi_pltentsz = 0;
    297 	mp->mi_dynsym.st_symn = 0;
    298 	while ((scn = elf_nextscn(mp->mi_elf, scn)) != NULL) {
    299 		GElf_Shdr 	shdr;
    300 		Elf_Data	*dp;
    301 		Elf_Scn		*tscn = NULL;
    302 
    303 		if (gelf_getshdr(scn, &shdr) == NULL) {
    304 			(void) printf("gelf_getshdr(): %s\n", elf_errmsg(-1));
    305 			(void) elf_end(mp->mi_elf);
    306 			return (RET_FAILED);
    307 		}
    308 
    309 		switch (shdr.sh_type) {
    310 		case SHT_DYNSYM:
    311 			dp = elf_getdata(scn, 0);
    312 			mp->mi_dynsym.st_syms_pri = dp;
    313 			tscn = elf_getscn(mp->mi_elf, shdr.sh_link);
    314 			mp->mi_dynsym.st_symn +=
    315 			    shdr.sh_size / shdr.sh_entsize;
    316 			dp = elf_getdata(tscn, 0);
    317 			mp->mi_dynsym.st_strs = (char *)dp->d_buf;
    318 			break;
    319 		case SHT_SUNW_LDYNSYM:
    320 			dp = elf_getdata(scn, 0);
    321 			mp->mi_dynsym.st_syms_aux = dp;
    322 			mp->mi_dynsym.st_symn_aux =
    323 			    shdr.sh_size / shdr.sh_entsize;
    324 			mp->mi_dynsym.st_symn += mp->mi_dynsym.st_symn_aux;
    325 			break;
    326 		case SHT_SYMTAB:
    327 			dp = elf_getdata(scn, 0);
    328 			mp->mi_symtab.st_syms_pri = dp;
    329 			tscn = elf_getscn(mp->mi_elf, shdr.sh_link);
    330 			mp->mi_symtab.st_symn =
    331 			    shdr.sh_size / shdr.sh_entsize;
    332 			dp = elf_getdata(tscn, 0);
    333 			mp->mi_symtab.st_strs = (char *)dp->d_buf;
    334 			break;
    335 		case PLTSECTT:
    336 			if (strcmp(PLTSECT, elf_strptr(mp->mi_elf,
    337 			    ehdr.e_shstrndx, shdr.sh_name)) == 0) {
    338 				mp->mi_pltbase = shdr.sh_addr;
    339 				mp->mi_pltsize = shdr.sh_size;
    340 				/* LINTED */
    341 				mp->mi_pltentsz = (unsigned)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 == 0) {
    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 	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