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