xref: /onnv-gate/usr/src/cmd/mdb/common/modules/libproc/libproc.c (revision 3347:5ae4cd56773a)
12712Snn35248 /*
22712Snn35248  * CDDL HEADER START
32712Snn35248  *
42712Snn35248  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
72712Snn35248  *
82712Snn35248  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92712Snn35248  * or http://www.opensolaris.org/os/licensing.
102712Snn35248  * See the License for the specific language governing permissions
112712Snn35248  * and limitations under the License.
122712Snn35248  *
132712Snn35248  * When distributing Covered Code, include this CDDL HEADER in each
142712Snn35248  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152712Snn35248  * If applicable, add the following below this CDDL HEADER, with the
162712Snn35248  * fields enclosed by brackets "[]" replaced with your own identifying
172712Snn35248  * information: Portions Copyright [yyyy] [name of copyright owner]
182712Snn35248  *
192712Snn35248  * CDDL HEADER END
202712Snn35248  */
212712Snn35248 /*
22*3347Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
232712Snn35248  * Use is subject to license terms.
242712Snn35248  */
252712Snn35248 
262712Snn35248 #pragma ident	"%Z%%M%	%I%	%E% SMI"
272712Snn35248 
282712Snn35248 #include <libproc.h>
292712Snn35248 #include <Pcontrol.h>
302712Snn35248 #include <stddef.h>
312712Snn35248 
322712Snn35248 #include <mdb/mdb_modapi.h>
332712Snn35248 
342712Snn35248 typedef struct ps_prochandle ps_prochandle_t;
352712Snn35248 
362712Snn35248 /*
372712Snn35248  * addr::pr_symtab [-a | n]
382712Snn35248  *
392712Snn35248  * 	-a	Sort symbols by address
402712Snn35248  * 	-n	Sort symbols by name
412712Snn35248  *
422712Snn35248  * Given a sym_tbl_t, dump its contents in tabular form.  When given '-a' or
432712Snn35248  * '-n', we use the sorted tables 'sym_byaddr' or 'sym_byname', respectively.
442712Snn35248  */
452712Snn35248 static int
pr_symtab(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)462712Snn35248 pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
472712Snn35248 {
482712Snn35248 	sym_tbl_t symtab;
49*3347Sab196087 	Elf_Data data_pri;
50*3347Sab196087 	Elf_Data data_aux;
51*3347Sab196087 	Elf_Data *data;
522712Snn35248 #ifdef _LP64
532712Snn35248 	Elf64_Sym sym;
542712Snn35248 	int width = 16;
552712Snn35248 #else
562712Snn35248 	Elf32_Sym sym;
572712Snn35248 	int width = 8;
582712Snn35248 #endif
592712Snn35248 	int i, idx, count;
602712Snn35248 	char name[128];
612712Snn35248 	int byaddr = FALSE;
622712Snn35248 	int byname = FALSE;
632712Snn35248 	uint_t *symlist;
642712Snn35248 	size_t symlistsz;
652712Snn35248 
662712Snn35248 	if (mdb_getopts(argc, argv,
672712Snn35248 	    'a', MDB_OPT_SETBITS, TRUE, &byaddr,
682712Snn35248 	    'n', MDB_OPT_SETBITS, TRUE, &byname,
692712Snn35248 	    NULL) != argc)
702712Snn35248 		return (DCMD_USAGE);
712712Snn35248 
722712Snn35248 	if (byaddr && byname) {
732712Snn35248 		mdb_warn("only one of '-a' or '-n' can be specified\n");
742712Snn35248 		return (DCMD_USAGE);
752712Snn35248 	}
762712Snn35248 
772712Snn35248 	if (!(flags & DCMD_ADDRSPEC))
782712Snn35248 		return (DCMD_USAGE);
792712Snn35248 
802712Snn35248 	if (mdb_vread(&symtab, sizeof (sym_tbl_t), addr) == -1) {
812712Snn35248 		mdb_warn("failed to read sym_tbl_t at %p", addr);
822712Snn35248 		return (DCMD_ERR);
832712Snn35248 	}
842712Snn35248 
852712Snn35248 	if (symtab.sym_count == 0) {
862712Snn35248 		mdb_warn("no symbols present\n");
872712Snn35248 		return (DCMD_ERR);
882712Snn35248 	}
892712Snn35248 
90*3347Sab196087 	/*
91*3347Sab196087 	 * As described in the libproc header Pcontrol.h, a sym_tbl_t
92*3347Sab196087 	 * contains a primary and an optional auxiliary symbol table.
93*3347Sab196087 	 * We treat the combination as a single table, with the auxiliary
94*3347Sab196087 	 * values coming before the primary ones.
95*3347Sab196087 	 *
96*3347Sab196087 	 * Read the primary and auxiliary Elf_Data structs.
97*3347Sab196087 	 */
98*3347Sab196087 	if (mdb_vread(&data_pri, sizeof (Elf_Data),
99*3347Sab196087 	    (uintptr_t)symtab.sym_data_pri) == -1) {
100*3347Sab196087 		mdb_warn("failed to read primary Elf_Data at %p",
101*3347Sab196087 		    symtab.sym_data_pri);
102*3347Sab196087 		return (DCMD_ERR);
103*3347Sab196087 	}
104*3347Sab196087 	if ((symtab.sym_symn_aux > 0) &&
105*3347Sab196087 	    (mdb_vread(&data_aux, sizeof (Elf_Data),
106*3347Sab196087 	    (uintptr_t)symtab.sym_data_aux) == -1)) {
107*3347Sab196087 		mdb_warn("failed to read auxiliary Elf_Data at %p",
108*3347Sab196087 		    symtab.sym_data_aux);
1092712Snn35248 		return (DCMD_ERR);
1102712Snn35248 	}
1112712Snn35248 
1122712Snn35248 	symlist = NULL;
1132712Snn35248 	if (byaddr || byname) {
1142712Snn35248 		uintptr_t src = byaddr ? (uintptr_t)symtab.sym_byaddr :
1152712Snn35248 		    (uintptr_t)symtab.sym_byname;
1162712Snn35248 
1172712Snn35248 		symlistsz = symtab.sym_count * sizeof (uint_t);
1182712Snn35248 		symlist = mdb_alloc(symlistsz, UM_SLEEP);
1192712Snn35248 		if (mdb_vread(symlist, symlistsz, src) == -1) {
1202712Snn35248 			mdb_warn("failed to read sorted symbols at %p", src);
1212712Snn35248 			return (DCMD_ERR);
1222712Snn35248 		}
1232712Snn35248 		count = symtab.sym_count;
1242712Snn35248 	} else {
1252712Snn35248 		count = symtab.sym_symn;
1262712Snn35248 	}
1272712Snn35248 
1282712Snn35248 	mdb_printf("%<u>%*s  %*s  %s%</u>\n", width, "ADDRESS", width,
1292712Snn35248 	    "SIZE", "NAME");
1302712Snn35248 
1312712Snn35248 	for (i = 0; i < count; i++) {
1322712Snn35248 		if (byaddr | byname)
1332712Snn35248 			idx = symlist[i];
1342712Snn35248 		else
1352712Snn35248 			idx = i;
1362712Snn35248 
137*3347Sab196087 		/* If index is in range of primary symtab, look it up there */
138*3347Sab196087 		if (idx >= symtab.sym_symn_aux) {
139*3347Sab196087 			data = &data_pri;
140*3347Sab196087 			idx -= symtab.sym_symn_aux;
141*3347Sab196087 		} else {	/* Look it up in the auxiliary symtab */
142*3347Sab196087 			data = &data_aux;
143*3347Sab196087 		}
144*3347Sab196087 
145*3347Sab196087 		if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data->d_buf +
1462712Snn35248 		    idx * sizeof (sym)) == -1) {
1472712Snn35248 			mdb_warn("failed to read symbol at %p",
148*3347Sab196087 			    (uintptr_t)data->d_buf + idx * sizeof (sym));
1492712Snn35248 			if (symlist)
1502712Snn35248 				mdb_free(symlist, symlistsz);
1512712Snn35248 			return (DCMD_ERR);
1522712Snn35248 		}
1532712Snn35248 
1542712Snn35248 		if (mdb_readstr(name, sizeof (name),
1552712Snn35248 		    (uintptr_t)symtab.sym_strs + sym.st_name) == -1) {
1562712Snn35248 			mdb_warn("failed to read symbol name at %p",
1572712Snn35248 			    symtab.sym_strs + sym.st_name);
1582712Snn35248 			name[0] = '\0';
1592712Snn35248 		}
1602712Snn35248 
1612712Snn35248 		mdb_printf("%0?p  %0?p  %s\n", sym.st_value, sym.st_size,
1622712Snn35248 		    name);
1632712Snn35248 	}
1642712Snn35248 
1652712Snn35248 	if (symlist)
1662712Snn35248 		mdb_free(symlist, symlistsz);
1672712Snn35248 
1682712Snn35248 	return (DCMD_OK);
1692712Snn35248 }
1702712Snn35248 
1712712Snn35248 /*
1722712Snn35248  * addr::pr_addr2map search
1732712Snn35248  *
1742712Snn35248  * Given a ps_prochandle_t, convert the given address to the corresponding
1752712Snn35248  * map_info_t.  Functionally equivalent to Paddr2mptr().
1762712Snn35248  */
1772712Snn35248 static int
pr_addr2map(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1782712Snn35248 pr_addr2map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1792712Snn35248 {
1802712Snn35248 	uintptr_t search;
1812712Snn35248 	ps_prochandle_t psp;
1822712Snn35248 	map_info_t *mp;
1832712Snn35248 	int lo, hi, mid;
1842712Snn35248 
1852712Snn35248 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
1862712Snn35248 		return (DCMD_USAGE);
1872712Snn35248 
1882712Snn35248 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
1892712Snn35248 		search = argv[0].a_un.a_val;
1902712Snn35248 	else
1912712Snn35248 		search = mdb_strtoull(argv[0].a_un.a_str);
1922712Snn35248 
1932712Snn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), addr) == -1) {
1942712Snn35248 		mdb_warn("failed to read ps_prochandle at %p", addr);
1952712Snn35248 		return (DCMD_ERR);
1962712Snn35248 	}
1972712Snn35248 
1982712Snn35248 	lo = 0;
1992712Snn35248 	hi = psp.map_count;
2002712Snn35248 	while (lo <= hi) {
2012712Snn35248 		mid = (lo + hi) / 2;
2022712Snn35248 		mp = &psp.mappings[mid];
2032712Snn35248 
2042712Snn35248 		if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size) {
2052712Snn35248 			mdb_printf("%#lr\n", addr + offsetof(ps_prochandle_t,
2062712Snn35248 			    mappings) + (mp - psp.mappings) *
2072712Snn35248 			    sizeof (map_info_t));
2082712Snn35248 			return (DCMD_OK);
2092712Snn35248 		}
2102712Snn35248 
2112712Snn35248 		if (addr < mp->map_pmap.pr_vaddr)
2122712Snn35248 			hi = mid - 1;
2132712Snn35248 		else
2142712Snn35248 			lo = mid + 1;
2152712Snn35248 	}
2162712Snn35248 
2172712Snn35248 	mdb_warn("no corresponding map for %p\n", search);
2182712Snn35248 	return (DCMD_ERR);
2192712Snn35248 }
2202712Snn35248 
2212712Snn35248 /*
2222712Snn35248  * ::walk pr_file_info
2232712Snn35248  *
2242712Snn35248  * Given a ps_prochandle_t, walk all its file_info_t structures.
2252712Snn35248  */
2262712Snn35248 typedef struct {
2272712Snn35248 	uintptr_t	fiw_next;
2282712Snn35248 	int		fiw_count;
2292712Snn35248 } file_info_walk_t;
2302712Snn35248 
2312712Snn35248 static int
pr_file_info_walk_init(mdb_walk_state_t * wsp)2322712Snn35248 pr_file_info_walk_init(mdb_walk_state_t *wsp)
2332712Snn35248 {
2342712Snn35248 	ps_prochandle_t psp;
2352712Snn35248 	file_info_walk_t *fiw;
2362712Snn35248 
2372712Snn35248 	if (wsp->walk_addr == NULL) {
2382712Snn35248 		mdb_warn("pr_file_info doesn't support global walks\n");
2392712Snn35248 		return (WALK_ERR);
2402712Snn35248 	}
2412712Snn35248 
2422712Snn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
2432712Snn35248 		mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
2442712Snn35248 		return (WALK_ERR);
2452712Snn35248 	}
2462712Snn35248 
2472712Snn35248 	fiw = mdb_alloc(sizeof (file_info_walk_t), UM_SLEEP);
2482712Snn35248 
2492712Snn35248 	fiw->fiw_next = (uintptr_t)psp.file_head.list_forw;
2502712Snn35248 	fiw->fiw_count = psp.num_files;
2512712Snn35248 	wsp->walk_data = fiw;
2522712Snn35248 
2532712Snn35248 	return (WALK_NEXT);
2542712Snn35248 }
2552712Snn35248 
2562712Snn35248 static int
pr_file_info_walk_step(mdb_walk_state_t * wsp)2572712Snn35248 pr_file_info_walk_step(mdb_walk_state_t *wsp)
2582712Snn35248 {
2592712Snn35248 	file_info_walk_t *fiw = wsp->walk_data;
2602712Snn35248 	file_info_t f;
2612712Snn35248 	int status;
2622712Snn35248 
2632712Snn35248 	if (fiw->fiw_count == 0)
2642712Snn35248 		return (WALK_DONE);
2652712Snn35248 
2662712Snn35248 	if (mdb_vread(&f, sizeof (file_info_t), fiw->fiw_next) == -1) {
2672712Snn35248 		mdb_warn("failed to read file_info_t at %p", fiw->fiw_next);
2682712Snn35248 		return (WALK_ERR);
2692712Snn35248 	}
2702712Snn35248 
2712712Snn35248 	status = wsp->walk_callback(fiw->fiw_next, &f, wsp->walk_cbdata);
2722712Snn35248 
2732712Snn35248 	fiw->fiw_next = (uintptr_t)f.file_list.list_forw;
2742712Snn35248 	fiw->fiw_count--;
2752712Snn35248 
2762712Snn35248 	return (status);
2772712Snn35248 }
2782712Snn35248 
2792712Snn35248 static void
pr_file_info_walk_fini(mdb_walk_state_t * wsp)2802712Snn35248 pr_file_info_walk_fini(mdb_walk_state_t *wsp)
2812712Snn35248 {
2822712Snn35248 	file_info_walk_t *fiw = wsp->walk_data;
2832712Snn35248 	mdb_free(fiw, sizeof (file_info_walk_t));
2842712Snn35248 }
2852712Snn35248 
2862712Snn35248 /*
2872712Snn35248  * ::walk pr_map_info
2882712Snn35248  *
2892712Snn35248  * Given a ps_prochandle_t, walk all its map_info_t structures.
2902712Snn35248  */
2912712Snn35248 typedef struct {
2922712Snn35248 	uintptr_t	miw_next;
2932712Snn35248 	int		miw_count;
2942712Snn35248 	int		miw_current;
2952712Snn35248 } map_info_walk_t;
2962712Snn35248 
2972712Snn35248 static int
pr_map_info_walk_init(mdb_walk_state_t * wsp)2982712Snn35248 pr_map_info_walk_init(mdb_walk_state_t *wsp)
2992712Snn35248 {
3002712Snn35248 	ps_prochandle_t psp;
3012712Snn35248 	map_info_walk_t *miw;
3022712Snn35248 
3032712Snn35248 	if (wsp->walk_addr == NULL) {
3042712Snn35248 		mdb_warn("pr_map_info doesn't support global walks\n");
3052712Snn35248 		return (WALK_ERR);
3062712Snn35248 	}
3072712Snn35248 
3082712Snn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
3092712Snn35248 		mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
3102712Snn35248 		return (WALK_ERR);
3112712Snn35248 	}
3122712Snn35248 
3132712Snn35248 	miw = mdb_alloc(sizeof (map_info_walk_t), UM_SLEEP);
3142712Snn35248 
3152712Snn35248 	miw->miw_next = (uintptr_t)psp.mappings;
3162712Snn35248 	miw->miw_count = psp.map_count;
3172712Snn35248 	miw->miw_current = 0;
3182712Snn35248 	wsp->walk_data = miw;
3192712Snn35248 
3202712Snn35248 	return (WALK_NEXT);
3212712Snn35248 }
3222712Snn35248 
3232712Snn35248 static int
pr_map_info_walk_step(mdb_walk_state_t * wsp)3242712Snn35248 pr_map_info_walk_step(mdb_walk_state_t *wsp)
3252712Snn35248 {
3262712Snn35248 	map_info_walk_t *miw = wsp->walk_data;
3272712Snn35248 	map_info_t m;
3282712Snn35248 	int status;
3292712Snn35248 
3302712Snn35248 	if (miw->miw_current == miw->miw_count)
3312712Snn35248 		return (WALK_DONE);
3322712Snn35248 
3332712Snn35248 	if (mdb_vread(&m, sizeof (map_info_t), miw->miw_next) == -1) {
3342712Snn35248 		mdb_warn("failed to read map_info_t at %p", miw->miw_next);
3352712Snn35248 		return (WALK_DONE);
3362712Snn35248 	}
3372712Snn35248 
3382712Snn35248 	status = wsp->walk_callback(miw->miw_next, &m, wsp->walk_cbdata);
3392712Snn35248 
3402712Snn35248 	miw->miw_current++;
3412712Snn35248 	miw->miw_next += sizeof (map_info_t);
3422712Snn35248 
3432712Snn35248 	return (status);
3442712Snn35248 }
3452712Snn35248 
3462712Snn35248 static void
pr_map_info_walk_fini(mdb_walk_state_t * wsp)3472712Snn35248 pr_map_info_walk_fini(mdb_walk_state_t *wsp)
3482712Snn35248 {
3492712Snn35248 	map_info_walk_t *miw = wsp->walk_data;
3502712Snn35248 	mdb_free(miw, sizeof (map_info_walk_t));
3512712Snn35248 }
3522712Snn35248 
3532712Snn35248 static const mdb_dcmd_t dcmds[] = {
3542712Snn35248 	{ "pr_addr2map",  ":addr", "convert an adress into a map_info_t",
3552712Snn35248 	    pr_addr2map },
3562712Snn35248 	{ "pr_symtab",	":[-a | -n]", "print the contents of a sym_tbl_t",
3572712Snn35248 	    pr_symtab },
3582712Snn35248 	{ NULL }
3592712Snn35248 };
3602712Snn35248 
3612712Snn35248 static const mdb_walker_t walkers[] = {
3622712Snn35248 	{ "pr_file_info", "given a ps_prochandle, walk its file_info "
3632712Snn35248 	    "structures", pr_file_info_walk_init, pr_file_info_walk_step,
3642712Snn35248 	    pr_file_info_walk_fini },
3652712Snn35248 	{ "pr_map_info", "given a ps_prochandle, walk its map_info structures",
3662712Snn35248 	    pr_map_info_walk_init, pr_map_info_walk_step,
3672712Snn35248 	    pr_map_info_walk_fini },
3682712Snn35248 	{ NULL }
3692712Snn35248 };
3702712Snn35248 
3712712Snn35248 static const mdb_modinfo_t modinfo = {
3722712Snn35248 	MDB_API_VERSION, dcmds, walkers
3732712Snn35248 };
3742712Snn35248 
3752712Snn35248 const mdb_modinfo_t *
_mdb_init(void)3762712Snn35248 _mdb_init(void)
3772712Snn35248 {
3782712Snn35248 	return (&modinfo);
3792712Snn35248 }
380