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