xref: /illumos-gate/usr/src/cmd/sgs/demo_rdb/common/maps.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
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