xref: /titanic_51/usr/src/cmd/mdb/common/modules/libproc/libproc.c (revision d51e90740114c60620c0febffd4d3ce6e280a107)
19acbbeafSnn35248 /*
29acbbeafSnn35248  * CDDL HEADER START
39acbbeafSnn35248  *
49acbbeafSnn35248  * The contents of this file are subject to the terms of the
59acbbeafSnn35248  * Common Development and Distribution License (the "License").
69acbbeafSnn35248  * You may not use this file except in compliance with the License.
79acbbeafSnn35248  *
89acbbeafSnn35248  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99acbbeafSnn35248  * or http://www.opensolaris.org/os/licensing.
109acbbeafSnn35248  * See the License for the specific language governing permissions
119acbbeafSnn35248  * and limitations under the License.
129acbbeafSnn35248  *
139acbbeafSnn35248  * When distributing Covered Code, include this CDDL HEADER in each
149acbbeafSnn35248  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159acbbeafSnn35248  * If applicable, add the following below this CDDL HEADER, with the
169acbbeafSnn35248  * fields enclosed by brackets "[]" replaced with your own identifying
179acbbeafSnn35248  * information: Portions Copyright [yyyy] [name of copyright owner]
189acbbeafSnn35248  *
199acbbeafSnn35248  * CDDL HEADER END
209acbbeafSnn35248  */
219acbbeafSnn35248 /*
22*d51e9074Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
239acbbeafSnn35248  * Use is subject to license terms.
249acbbeafSnn35248  */
259acbbeafSnn35248 
269acbbeafSnn35248 #pragma ident	"%Z%%M%	%I%	%E% SMI"
279acbbeafSnn35248 
289acbbeafSnn35248 #include <libproc.h>
299acbbeafSnn35248 #include <Pcontrol.h>
309acbbeafSnn35248 #include <stddef.h>
319acbbeafSnn35248 
329acbbeafSnn35248 #include <mdb/mdb_modapi.h>
339acbbeafSnn35248 
349acbbeafSnn35248 typedef struct ps_prochandle ps_prochandle_t;
359acbbeafSnn35248 
369acbbeafSnn35248 /*
379acbbeafSnn35248  * addr::pr_symtab [-a | n]
389acbbeafSnn35248  *
399acbbeafSnn35248  * 	-a	Sort symbols by address
409acbbeafSnn35248  * 	-n	Sort symbols by name
419acbbeafSnn35248  *
429acbbeafSnn35248  * Given a sym_tbl_t, dump its contents in tabular form.  When given '-a' or
439acbbeafSnn35248  * '-n', we use the sorted tables 'sym_byaddr' or 'sym_byname', respectively.
449acbbeafSnn35248  */
459acbbeafSnn35248 static int
469acbbeafSnn35248 pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
479acbbeafSnn35248 {
489acbbeafSnn35248 	sym_tbl_t symtab;
49*d51e9074Sab196087 	Elf_Data data_pri;
50*d51e9074Sab196087 	Elf_Data data_aux;
51*d51e9074Sab196087 	Elf_Data *data;
529acbbeafSnn35248 #ifdef _LP64
539acbbeafSnn35248 	Elf64_Sym sym;
549acbbeafSnn35248 	int width = 16;
559acbbeafSnn35248 #else
569acbbeafSnn35248 	Elf32_Sym sym;
579acbbeafSnn35248 	int width = 8;
589acbbeafSnn35248 #endif
599acbbeafSnn35248 	int i, idx, count;
609acbbeafSnn35248 	char name[128];
619acbbeafSnn35248 	int byaddr = FALSE;
629acbbeafSnn35248 	int byname = FALSE;
639acbbeafSnn35248 	uint_t *symlist;
649acbbeafSnn35248 	size_t symlistsz;
659acbbeafSnn35248 
669acbbeafSnn35248 	if (mdb_getopts(argc, argv,
679acbbeafSnn35248 	    'a', MDB_OPT_SETBITS, TRUE, &byaddr,
689acbbeafSnn35248 	    'n', MDB_OPT_SETBITS, TRUE, &byname,
699acbbeafSnn35248 	    NULL) != argc)
709acbbeafSnn35248 		return (DCMD_USAGE);
719acbbeafSnn35248 
729acbbeafSnn35248 	if (byaddr && byname) {
739acbbeafSnn35248 		mdb_warn("only one of '-a' or '-n' can be specified\n");
749acbbeafSnn35248 		return (DCMD_USAGE);
759acbbeafSnn35248 	}
769acbbeafSnn35248 
779acbbeafSnn35248 	if (!(flags & DCMD_ADDRSPEC))
789acbbeafSnn35248 		return (DCMD_USAGE);
799acbbeafSnn35248 
809acbbeafSnn35248 	if (mdb_vread(&symtab, sizeof (sym_tbl_t), addr) == -1) {
819acbbeafSnn35248 		mdb_warn("failed to read sym_tbl_t at %p", addr);
829acbbeafSnn35248 		return (DCMD_ERR);
839acbbeafSnn35248 	}
849acbbeafSnn35248 
859acbbeafSnn35248 	if (symtab.sym_count == 0) {
869acbbeafSnn35248 		mdb_warn("no symbols present\n");
879acbbeafSnn35248 		return (DCMD_ERR);
889acbbeafSnn35248 	}
899acbbeafSnn35248 
90*d51e9074Sab196087 	/*
91*d51e9074Sab196087 	 * As described in the libproc header Pcontrol.h, a sym_tbl_t
92*d51e9074Sab196087 	 * contains a primary and an optional auxiliary symbol table.
93*d51e9074Sab196087 	 * We treat the combination as a single table, with the auxiliary
94*d51e9074Sab196087 	 * values coming before the primary ones.
95*d51e9074Sab196087 	 *
96*d51e9074Sab196087 	 * Read the primary and auxiliary Elf_Data structs.
97*d51e9074Sab196087 	 */
98*d51e9074Sab196087 	if (mdb_vread(&data_pri, sizeof (Elf_Data),
99*d51e9074Sab196087 	    (uintptr_t)symtab.sym_data_pri) == -1) {
100*d51e9074Sab196087 		mdb_warn("failed to read primary Elf_Data at %p",
101*d51e9074Sab196087 		    symtab.sym_data_pri);
102*d51e9074Sab196087 		return (DCMD_ERR);
103*d51e9074Sab196087 	}
104*d51e9074Sab196087 	if ((symtab.sym_symn_aux > 0) &&
105*d51e9074Sab196087 	    (mdb_vread(&data_aux, sizeof (Elf_Data),
106*d51e9074Sab196087 	    (uintptr_t)symtab.sym_data_aux) == -1)) {
107*d51e9074Sab196087 		mdb_warn("failed to read auxiliary Elf_Data at %p",
108*d51e9074Sab196087 		    symtab.sym_data_aux);
1099acbbeafSnn35248 		return (DCMD_ERR);
1109acbbeafSnn35248 	}
1119acbbeafSnn35248 
1129acbbeafSnn35248 	symlist = NULL;
1139acbbeafSnn35248 	if (byaddr || byname) {
1149acbbeafSnn35248 		uintptr_t src = byaddr ? (uintptr_t)symtab.sym_byaddr :
1159acbbeafSnn35248 		    (uintptr_t)symtab.sym_byname;
1169acbbeafSnn35248 
1179acbbeafSnn35248 		symlistsz = symtab.sym_count * sizeof (uint_t);
1189acbbeafSnn35248 		symlist = mdb_alloc(symlistsz, UM_SLEEP);
1199acbbeafSnn35248 		if (mdb_vread(symlist, symlistsz, src) == -1) {
1209acbbeafSnn35248 			mdb_warn("failed to read sorted symbols at %p", src);
1219acbbeafSnn35248 			return (DCMD_ERR);
1229acbbeafSnn35248 		}
1239acbbeafSnn35248 		count = symtab.sym_count;
1249acbbeafSnn35248 	} else {
1259acbbeafSnn35248 		count = symtab.sym_symn;
1269acbbeafSnn35248 	}
1279acbbeafSnn35248 
1289acbbeafSnn35248 	mdb_printf("%<u>%*s  %*s  %s%</u>\n", width, "ADDRESS", width,
1299acbbeafSnn35248 	    "SIZE", "NAME");
1309acbbeafSnn35248 
1319acbbeafSnn35248 	for (i = 0; i < count; i++) {
1329acbbeafSnn35248 		if (byaddr | byname)
1339acbbeafSnn35248 			idx = symlist[i];
1349acbbeafSnn35248 		else
1359acbbeafSnn35248 			idx = i;
1369acbbeafSnn35248 
137*d51e9074Sab196087 		/* If index is in range of primary symtab, look it up there */
138*d51e9074Sab196087 		if (idx >= symtab.sym_symn_aux) {
139*d51e9074Sab196087 			data = &data_pri;
140*d51e9074Sab196087 			idx -= symtab.sym_symn_aux;
141*d51e9074Sab196087 		} else {	/* Look it up in the auxiliary symtab */
142*d51e9074Sab196087 			data = &data_aux;
143*d51e9074Sab196087 		}
144*d51e9074Sab196087 
145*d51e9074Sab196087 		if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data->d_buf +
1469acbbeafSnn35248 		    idx * sizeof (sym)) == -1) {
1479acbbeafSnn35248 			mdb_warn("failed to read symbol at %p",
148*d51e9074Sab196087 			    (uintptr_t)data->d_buf + idx * sizeof (sym));
1499acbbeafSnn35248 			if (symlist)
1509acbbeafSnn35248 				mdb_free(symlist, symlistsz);
1519acbbeafSnn35248 			return (DCMD_ERR);
1529acbbeafSnn35248 		}
1539acbbeafSnn35248 
1549acbbeafSnn35248 		if (mdb_readstr(name, sizeof (name),
1559acbbeafSnn35248 		    (uintptr_t)symtab.sym_strs + sym.st_name) == -1) {
1569acbbeafSnn35248 			mdb_warn("failed to read symbol name at %p",
1579acbbeafSnn35248 			    symtab.sym_strs + sym.st_name);
1589acbbeafSnn35248 			name[0] = '\0';
1599acbbeafSnn35248 		}
1609acbbeafSnn35248 
1619acbbeafSnn35248 		mdb_printf("%0?p  %0?p  %s\n", sym.st_value, sym.st_size,
1629acbbeafSnn35248 		    name);
1639acbbeafSnn35248 	}
1649acbbeafSnn35248 
1659acbbeafSnn35248 	if (symlist)
1669acbbeafSnn35248 		mdb_free(symlist, symlistsz);
1679acbbeafSnn35248 
1689acbbeafSnn35248 	return (DCMD_OK);
1699acbbeafSnn35248 }
1709acbbeafSnn35248 
1719acbbeafSnn35248 /*
1729acbbeafSnn35248  * addr::pr_addr2map search
1739acbbeafSnn35248  *
1749acbbeafSnn35248  * Given a ps_prochandle_t, convert the given address to the corresponding
1759acbbeafSnn35248  * map_info_t.  Functionally equivalent to Paddr2mptr().
1769acbbeafSnn35248  */
1779acbbeafSnn35248 static int
1789acbbeafSnn35248 pr_addr2map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1799acbbeafSnn35248 {
1809acbbeafSnn35248 	uintptr_t search;
1819acbbeafSnn35248 	ps_prochandle_t psp;
1829acbbeafSnn35248 	map_info_t *mp;
1839acbbeafSnn35248 	int lo, hi, mid;
1849acbbeafSnn35248 
1859acbbeafSnn35248 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
1869acbbeafSnn35248 		return (DCMD_USAGE);
1879acbbeafSnn35248 
1889acbbeafSnn35248 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
1899acbbeafSnn35248 		search = argv[0].a_un.a_val;
1909acbbeafSnn35248 	else
1919acbbeafSnn35248 		search = mdb_strtoull(argv[0].a_un.a_str);
1929acbbeafSnn35248 
1939acbbeafSnn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), addr) == -1) {
1949acbbeafSnn35248 		mdb_warn("failed to read ps_prochandle at %p", addr);
1959acbbeafSnn35248 		return (DCMD_ERR);
1969acbbeafSnn35248 	}
1979acbbeafSnn35248 
1989acbbeafSnn35248 	lo = 0;
1999acbbeafSnn35248 	hi = psp.map_count;
2009acbbeafSnn35248 	while (lo <= hi) {
2019acbbeafSnn35248 		mid = (lo + hi) / 2;
2029acbbeafSnn35248 		mp = &psp.mappings[mid];
2039acbbeafSnn35248 
2049acbbeafSnn35248 		if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size) {
2059acbbeafSnn35248 			mdb_printf("%#lr\n", addr + offsetof(ps_prochandle_t,
2069acbbeafSnn35248 			    mappings) + (mp - psp.mappings) *
2079acbbeafSnn35248 			    sizeof (map_info_t));
2089acbbeafSnn35248 			return (DCMD_OK);
2099acbbeafSnn35248 		}
2109acbbeafSnn35248 
2119acbbeafSnn35248 		if (addr < mp->map_pmap.pr_vaddr)
2129acbbeafSnn35248 			hi = mid - 1;
2139acbbeafSnn35248 		else
2149acbbeafSnn35248 			lo = mid + 1;
2159acbbeafSnn35248 	}
2169acbbeafSnn35248 
2179acbbeafSnn35248 	mdb_warn("no corresponding map for %p\n", search);
2189acbbeafSnn35248 	return (DCMD_ERR);
2199acbbeafSnn35248 }
2209acbbeafSnn35248 
2219acbbeafSnn35248 /*
2229acbbeafSnn35248  * ::walk pr_file_info
2239acbbeafSnn35248  *
2249acbbeafSnn35248  * Given a ps_prochandle_t, walk all its file_info_t structures.
2259acbbeafSnn35248  */
2269acbbeafSnn35248 typedef struct {
2279acbbeafSnn35248 	uintptr_t	fiw_next;
2289acbbeafSnn35248 	int		fiw_count;
2299acbbeafSnn35248 } file_info_walk_t;
2309acbbeafSnn35248 
2319acbbeafSnn35248 static int
2329acbbeafSnn35248 pr_file_info_walk_init(mdb_walk_state_t *wsp)
2339acbbeafSnn35248 {
2349acbbeafSnn35248 	ps_prochandle_t psp;
2359acbbeafSnn35248 	file_info_walk_t *fiw;
2369acbbeafSnn35248 
2379acbbeafSnn35248 	if (wsp->walk_addr == NULL) {
2389acbbeafSnn35248 		mdb_warn("pr_file_info doesn't support global walks\n");
2399acbbeafSnn35248 		return (WALK_ERR);
2409acbbeafSnn35248 	}
2419acbbeafSnn35248 
2429acbbeafSnn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
2439acbbeafSnn35248 		mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
2449acbbeafSnn35248 		return (WALK_ERR);
2459acbbeafSnn35248 	}
2469acbbeafSnn35248 
2479acbbeafSnn35248 	fiw = mdb_alloc(sizeof (file_info_walk_t), UM_SLEEP);
2489acbbeafSnn35248 
2499acbbeafSnn35248 	fiw->fiw_next = (uintptr_t)psp.file_head.list_forw;
2509acbbeafSnn35248 	fiw->fiw_count = psp.num_files;
2519acbbeafSnn35248 	wsp->walk_data = fiw;
2529acbbeafSnn35248 
2539acbbeafSnn35248 	return (WALK_NEXT);
2549acbbeafSnn35248 }
2559acbbeafSnn35248 
2569acbbeafSnn35248 static int
2579acbbeafSnn35248 pr_file_info_walk_step(mdb_walk_state_t *wsp)
2589acbbeafSnn35248 {
2599acbbeafSnn35248 	file_info_walk_t *fiw = wsp->walk_data;
2609acbbeafSnn35248 	file_info_t f;
2619acbbeafSnn35248 	int status;
2629acbbeafSnn35248 
2639acbbeafSnn35248 	if (fiw->fiw_count == 0)
2649acbbeafSnn35248 		return (WALK_DONE);
2659acbbeafSnn35248 
2669acbbeafSnn35248 	if (mdb_vread(&f, sizeof (file_info_t), fiw->fiw_next) == -1) {
2679acbbeafSnn35248 		mdb_warn("failed to read file_info_t at %p", fiw->fiw_next);
2689acbbeafSnn35248 		return (WALK_ERR);
2699acbbeafSnn35248 	}
2709acbbeafSnn35248 
2719acbbeafSnn35248 	status = wsp->walk_callback(fiw->fiw_next, &f, wsp->walk_cbdata);
2729acbbeafSnn35248 
2739acbbeafSnn35248 	fiw->fiw_next = (uintptr_t)f.file_list.list_forw;
2749acbbeafSnn35248 	fiw->fiw_count--;
2759acbbeafSnn35248 
2769acbbeafSnn35248 	return (status);
2779acbbeafSnn35248 }
2789acbbeafSnn35248 
2799acbbeafSnn35248 static void
2809acbbeafSnn35248 pr_file_info_walk_fini(mdb_walk_state_t *wsp)
2819acbbeafSnn35248 {
2829acbbeafSnn35248 	file_info_walk_t *fiw = wsp->walk_data;
2839acbbeafSnn35248 	mdb_free(fiw, sizeof (file_info_walk_t));
2849acbbeafSnn35248 }
2859acbbeafSnn35248 
2869acbbeafSnn35248 /*
2879acbbeafSnn35248  * ::walk pr_map_info
2889acbbeafSnn35248  *
2899acbbeafSnn35248  * Given a ps_prochandle_t, walk all its map_info_t structures.
2909acbbeafSnn35248  */
2919acbbeafSnn35248 typedef struct {
2929acbbeafSnn35248 	uintptr_t	miw_next;
2939acbbeafSnn35248 	int		miw_count;
2949acbbeafSnn35248 	int		miw_current;
2959acbbeafSnn35248 } map_info_walk_t;
2969acbbeafSnn35248 
2979acbbeafSnn35248 static int
2989acbbeafSnn35248 pr_map_info_walk_init(mdb_walk_state_t *wsp)
2999acbbeafSnn35248 {
3009acbbeafSnn35248 	ps_prochandle_t psp;
3019acbbeafSnn35248 	map_info_walk_t *miw;
3029acbbeafSnn35248 
3039acbbeafSnn35248 	if (wsp->walk_addr == NULL) {
3049acbbeafSnn35248 		mdb_warn("pr_map_info doesn't support global walks\n");
3059acbbeafSnn35248 		return (WALK_ERR);
3069acbbeafSnn35248 	}
3079acbbeafSnn35248 
3089acbbeafSnn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
3099acbbeafSnn35248 		mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
3109acbbeafSnn35248 		return (WALK_ERR);
3119acbbeafSnn35248 	}
3129acbbeafSnn35248 
3139acbbeafSnn35248 	miw = mdb_alloc(sizeof (map_info_walk_t), UM_SLEEP);
3149acbbeafSnn35248 
3159acbbeafSnn35248 	miw->miw_next = (uintptr_t)psp.mappings;
3169acbbeafSnn35248 	miw->miw_count = psp.map_count;
3179acbbeafSnn35248 	miw->miw_current = 0;
3189acbbeafSnn35248 	wsp->walk_data = miw;
3199acbbeafSnn35248 
3209acbbeafSnn35248 	return (WALK_NEXT);
3219acbbeafSnn35248 }
3229acbbeafSnn35248 
3239acbbeafSnn35248 static int
3249acbbeafSnn35248 pr_map_info_walk_step(mdb_walk_state_t *wsp)
3259acbbeafSnn35248 {
3269acbbeafSnn35248 	map_info_walk_t *miw = wsp->walk_data;
3279acbbeafSnn35248 	map_info_t m;
3289acbbeafSnn35248 	int status;
3299acbbeafSnn35248 
3309acbbeafSnn35248 	if (miw->miw_current == miw->miw_count)
3319acbbeafSnn35248 		return (WALK_DONE);
3329acbbeafSnn35248 
3339acbbeafSnn35248 	if (mdb_vread(&m, sizeof (map_info_t), miw->miw_next) == -1) {
3349acbbeafSnn35248 		mdb_warn("failed to read map_info_t at %p", miw->miw_next);
3359acbbeafSnn35248 		return (WALK_DONE);
3369acbbeafSnn35248 	}
3379acbbeafSnn35248 
3389acbbeafSnn35248 	status = wsp->walk_callback(miw->miw_next, &m, wsp->walk_cbdata);
3399acbbeafSnn35248 
3409acbbeafSnn35248 	miw->miw_current++;
3419acbbeafSnn35248 	miw->miw_next += sizeof (map_info_t);
3429acbbeafSnn35248 
3439acbbeafSnn35248 	return (status);
3449acbbeafSnn35248 }
3459acbbeafSnn35248 
3469acbbeafSnn35248 static void
3479acbbeafSnn35248 pr_map_info_walk_fini(mdb_walk_state_t *wsp)
3489acbbeafSnn35248 {
3499acbbeafSnn35248 	map_info_walk_t *miw = wsp->walk_data;
3509acbbeafSnn35248 	mdb_free(miw, sizeof (map_info_walk_t));
3519acbbeafSnn35248 }
3529acbbeafSnn35248 
3539acbbeafSnn35248 static const mdb_dcmd_t dcmds[] = {
3549acbbeafSnn35248 	{ "pr_addr2map",  ":addr", "convert an adress into a map_info_t",
3559acbbeafSnn35248 	    pr_addr2map },
3569acbbeafSnn35248 	{ "pr_symtab",	":[-a | -n]", "print the contents of a sym_tbl_t",
3579acbbeafSnn35248 	    pr_symtab },
3589acbbeafSnn35248 	{ NULL }
3599acbbeafSnn35248 };
3609acbbeafSnn35248 
3619acbbeafSnn35248 static const mdb_walker_t walkers[] = {
3629acbbeafSnn35248 	{ "pr_file_info", "given a ps_prochandle, walk its file_info "
3639acbbeafSnn35248 	    "structures", pr_file_info_walk_init, pr_file_info_walk_step,
3649acbbeafSnn35248 	    pr_file_info_walk_fini },
3659acbbeafSnn35248 	{ "pr_map_info", "given a ps_prochandle, walk its map_info structures",
3669acbbeafSnn35248 	    pr_map_info_walk_init, pr_map_info_walk_step,
3679acbbeafSnn35248 	    pr_map_info_walk_fini },
3689acbbeafSnn35248 	{ NULL }
3699acbbeafSnn35248 };
3709acbbeafSnn35248 
3719acbbeafSnn35248 static const mdb_modinfo_t modinfo = {
3729acbbeafSnn35248 	MDB_API_VERSION, dcmds, walkers
3739acbbeafSnn35248 };
3749acbbeafSnn35248 
3759acbbeafSnn35248 const mdb_modinfo_t *
3769acbbeafSnn35248 _mdb_init(void)
3779acbbeafSnn35248 {
3789acbbeafSnn35248 	return (&modinfo);
3799acbbeafSnn35248 }
380