1*2712Snn35248 /* 2*2712Snn35248 * CDDL HEADER START 3*2712Snn35248 * 4*2712Snn35248 * The contents of this file are subject to the terms of the 5*2712Snn35248 * Common Development and Distribution License (the "License"). 6*2712Snn35248 * You may not use this file except in compliance with the License. 7*2712Snn35248 * 8*2712Snn35248 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2712Snn35248 * or http://www.opensolaris.org/os/licensing. 10*2712Snn35248 * See the License for the specific language governing permissions 11*2712Snn35248 * and limitations under the License. 12*2712Snn35248 * 13*2712Snn35248 * When distributing Covered Code, include this CDDL HEADER in each 14*2712Snn35248 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2712Snn35248 * If applicable, add the following below this CDDL HEADER, with the 16*2712Snn35248 * fields enclosed by brackets "[]" replaced with your own identifying 17*2712Snn35248 * information: Portions Copyright [yyyy] [name of copyright owner] 18*2712Snn35248 * 19*2712Snn35248 * CDDL HEADER END 20*2712Snn35248 */ 21*2712Snn35248 /* 22*2712Snn35248 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*2712Snn35248 * Use is subject to license terms. 24*2712Snn35248 */ 25*2712Snn35248 26*2712Snn35248 #pragma ident "%Z%%M% %I% %E% SMI" 27*2712Snn35248 28*2712Snn35248 #include <libproc.h> 29*2712Snn35248 #include <Pcontrol.h> 30*2712Snn35248 #include <stddef.h> 31*2712Snn35248 32*2712Snn35248 #include <mdb/mdb_modapi.h> 33*2712Snn35248 34*2712Snn35248 typedef struct ps_prochandle ps_prochandle_t; 35*2712Snn35248 36*2712Snn35248 /* 37*2712Snn35248 * addr::pr_symtab [-a | n] 38*2712Snn35248 * 39*2712Snn35248 * -a Sort symbols by address 40*2712Snn35248 * -n Sort symbols by name 41*2712Snn35248 * 42*2712Snn35248 * Given a sym_tbl_t, dump its contents in tabular form. When given '-a' or 43*2712Snn35248 * '-n', we use the sorted tables 'sym_byaddr' or 'sym_byname', respectively. 44*2712Snn35248 */ 45*2712Snn35248 static int 46*2712Snn35248 pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 47*2712Snn35248 { 48*2712Snn35248 sym_tbl_t symtab; 49*2712Snn35248 Elf_Data data; 50*2712Snn35248 #ifdef _LP64 51*2712Snn35248 Elf64_Sym sym; 52*2712Snn35248 int width = 16; 53*2712Snn35248 #else 54*2712Snn35248 Elf32_Sym sym; 55*2712Snn35248 int width = 8; 56*2712Snn35248 #endif 57*2712Snn35248 int i, idx, count; 58*2712Snn35248 char name[128]; 59*2712Snn35248 int byaddr = FALSE; 60*2712Snn35248 int byname = FALSE; 61*2712Snn35248 uint_t *symlist; 62*2712Snn35248 size_t symlistsz; 63*2712Snn35248 64*2712Snn35248 if (mdb_getopts(argc, argv, 65*2712Snn35248 'a', MDB_OPT_SETBITS, TRUE, &byaddr, 66*2712Snn35248 'n', MDB_OPT_SETBITS, TRUE, &byname, 67*2712Snn35248 NULL) != argc) 68*2712Snn35248 return (DCMD_USAGE); 69*2712Snn35248 70*2712Snn35248 if (byaddr && byname) { 71*2712Snn35248 mdb_warn("only one of '-a' or '-n' can be specified\n"); 72*2712Snn35248 return (DCMD_USAGE); 73*2712Snn35248 } 74*2712Snn35248 75*2712Snn35248 if (!(flags & DCMD_ADDRSPEC)) 76*2712Snn35248 return (DCMD_USAGE); 77*2712Snn35248 78*2712Snn35248 if (mdb_vread(&symtab, sizeof (sym_tbl_t), addr) == -1) { 79*2712Snn35248 mdb_warn("failed to read sym_tbl_t at %p", addr); 80*2712Snn35248 return (DCMD_ERR); 81*2712Snn35248 } 82*2712Snn35248 83*2712Snn35248 if (symtab.sym_count == 0) { 84*2712Snn35248 mdb_warn("no symbols present\n"); 85*2712Snn35248 return (DCMD_ERR); 86*2712Snn35248 } 87*2712Snn35248 88*2712Snn35248 if (mdb_vread(&data, sizeof (Elf_Data), 89*2712Snn35248 (uintptr_t)symtab.sym_data) == -1) { 90*2712Snn35248 mdb_warn("failed to read Elf_Data at %p", symtab.sym_data); 91*2712Snn35248 return (DCMD_ERR); 92*2712Snn35248 } 93*2712Snn35248 94*2712Snn35248 symlist = NULL; 95*2712Snn35248 if (byaddr || byname) { 96*2712Snn35248 uintptr_t src = byaddr ? (uintptr_t)symtab.sym_byaddr : 97*2712Snn35248 (uintptr_t)symtab.sym_byname; 98*2712Snn35248 99*2712Snn35248 symlistsz = symtab.sym_count * sizeof (uint_t); 100*2712Snn35248 symlist = mdb_alloc(symlistsz, UM_SLEEP); 101*2712Snn35248 if (mdb_vread(symlist, symlistsz, src) == -1) { 102*2712Snn35248 mdb_warn("failed to read sorted symbols at %p", src); 103*2712Snn35248 return (DCMD_ERR); 104*2712Snn35248 } 105*2712Snn35248 count = symtab.sym_count; 106*2712Snn35248 } else { 107*2712Snn35248 count = symtab.sym_symn; 108*2712Snn35248 } 109*2712Snn35248 110*2712Snn35248 mdb_printf("%<u>%*s %*s %s%</u>\n", width, "ADDRESS", width, 111*2712Snn35248 "SIZE", "NAME"); 112*2712Snn35248 113*2712Snn35248 for (i = 0; i < count; i++) { 114*2712Snn35248 if (byaddr | byname) 115*2712Snn35248 idx = symlist[i]; 116*2712Snn35248 else 117*2712Snn35248 idx = i; 118*2712Snn35248 119*2712Snn35248 if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data.d_buf + 120*2712Snn35248 idx * sizeof (sym)) == -1) { 121*2712Snn35248 mdb_warn("failed to read symbol at %p", 122*2712Snn35248 (uintptr_t)data.d_buf + idx * sizeof (sym)); 123*2712Snn35248 if (symlist) 124*2712Snn35248 mdb_free(symlist, symlistsz); 125*2712Snn35248 return (DCMD_ERR); 126*2712Snn35248 } 127*2712Snn35248 128*2712Snn35248 if (mdb_readstr(name, sizeof (name), 129*2712Snn35248 (uintptr_t)symtab.sym_strs + sym.st_name) == -1) { 130*2712Snn35248 mdb_warn("failed to read symbol name at %p", 131*2712Snn35248 symtab.sym_strs + sym.st_name); 132*2712Snn35248 name[0] = '\0'; 133*2712Snn35248 } 134*2712Snn35248 135*2712Snn35248 mdb_printf("%0?p %0?p %s\n", sym.st_value, sym.st_size, 136*2712Snn35248 name); 137*2712Snn35248 } 138*2712Snn35248 139*2712Snn35248 if (symlist) 140*2712Snn35248 mdb_free(symlist, symlistsz); 141*2712Snn35248 142*2712Snn35248 return (DCMD_OK); 143*2712Snn35248 } 144*2712Snn35248 145*2712Snn35248 /* 146*2712Snn35248 * addr::pr_addr2map search 147*2712Snn35248 * 148*2712Snn35248 * Given a ps_prochandle_t, convert the given address to the corresponding 149*2712Snn35248 * map_info_t. Functionally equivalent to Paddr2mptr(). 150*2712Snn35248 */ 151*2712Snn35248 static int 152*2712Snn35248 pr_addr2map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 153*2712Snn35248 { 154*2712Snn35248 uintptr_t search; 155*2712Snn35248 ps_prochandle_t psp; 156*2712Snn35248 map_info_t *mp; 157*2712Snn35248 int lo, hi, mid; 158*2712Snn35248 159*2712Snn35248 if (!(flags & DCMD_ADDRSPEC) || argc != 1) 160*2712Snn35248 return (DCMD_USAGE); 161*2712Snn35248 162*2712Snn35248 if (argv[0].a_type == MDB_TYPE_IMMEDIATE) 163*2712Snn35248 search = argv[0].a_un.a_val; 164*2712Snn35248 else 165*2712Snn35248 search = mdb_strtoull(argv[0].a_un.a_str); 166*2712Snn35248 167*2712Snn35248 if (mdb_vread(&psp, sizeof (ps_prochandle_t), addr) == -1) { 168*2712Snn35248 mdb_warn("failed to read ps_prochandle at %p", addr); 169*2712Snn35248 return (DCMD_ERR); 170*2712Snn35248 } 171*2712Snn35248 172*2712Snn35248 lo = 0; 173*2712Snn35248 hi = psp.map_count; 174*2712Snn35248 while (lo <= hi) { 175*2712Snn35248 mid = (lo + hi) / 2; 176*2712Snn35248 mp = &psp.mappings[mid]; 177*2712Snn35248 178*2712Snn35248 if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size) { 179*2712Snn35248 mdb_printf("%#lr\n", addr + offsetof(ps_prochandle_t, 180*2712Snn35248 mappings) + (mp - psp.mappings) * 181*2712Snn35248 sizeof (map_info_t)); 182*2712Snn35248 return (DCMD_OK); 183*2712Snn35248 } 184*2712Snn35248 185*2712Snn35248 if (addr < mp->map_pmap.pr_vaddr) 186*2712Snn35248 hi = mid - 1; 187*2712Snn35248 else 188*2712Snn35248 lo = mid + 1; 189*2712Snn35248 } 190*2712Snn35248 191*2712Snn35248 mdb_warn("no corresponding map for %p\n", search); 192*2712Snn35248 return (DCMD_ERR); 193*2712Snn35248 } 194*2712Snn35248 195*2712Snn35248 /* 196*2712Snn35248 * ::walk pr_file_info 197*2712Snn35248 * 198*2712Snn35248 * Given a ps_prochandle_t, walk all its file_info_t structures. 199*2712Snn35248 */ 200*2712Snn35248 typedef struct { 201*2712Snn35248 uintptr_t fiw_next; 202*2712Snn35248 int fiw_count; 203*2712Snn35248 } file_info_walk_t; 204*2712Snn35248 205*2712Snn35248 static int 206*2712Snn35248 pr_file_info_walk_init(mdb_walk_state_t *wsp) 207*2712Snn35248 { 208*2712Snn35248 ps_prochandle_t psp; 209*2712Snn35248 file_info_walk_t *fiw; 210*2712Snn35248 211*2712Snn35248 if (wsp->walk_addr == NULL) { 212*2712Snn35248 mdb_warn("pr_file_info doesn't support global walks\n"); 213*2712Snn35248 return (WALK_ERR); 214*2712Snn35248 } 215*2712Snn35248 216*2712Snn35248 if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) { 217*2712Snn35248 mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr); 218*2712Snn35248 return (WALK_ERR); 219*2712Snn35248 } 220*2712Snn35248 221*2712Snn35248 fiw = mdb_alloc(sizeof (file_info_walk_t), UM_SLEEP); 222*2712Snn35248 223*2712Snn35248 fiw->fiw_next = (uintptr_t)psp.file_head.list_forw; 224*2712Snn35248 fiw->fiw_count = psp.num_files; 225*2712Snn35248 wsp->walk_data = fiw; 226*2712Snn35248 227*2712Snn35248 return (WALK_NEXT); 228*2712Snn35248 } 229*2712Snn35248 230*2712Snn35248 static int 231*2712Snn35248 pr_file_info_walk_step(mdb_walk_state_t *wsp) 232*2712Snn35248 { 233*2712Snn35248 file_info_walk_t *fiw = wsp->walk_data; 234*2712Snn35248 file_info_t f; 235*2712Snn35248 int status; 236*2712Snn35248 237*2712Snn35248 if (fiw->fiw_count == 0) 238*2712Snn35248 return (WALK_DONE); 239*2712Snn35248 240*2712Snn35248 if (mdb_vread(&f, sizeof (file_info_t), fiw->fiw_next) == -1) { 241*2712Snn35248 mdb_warn("failed to read file_info_t at %p", fiw->fiw_next); 242*2712Snn35248 return (WALK_ERR); 243*2712Snn35248 } 244*2712Snn35248 245*2712Snn35248 status = wsp->walk_callback(fiw->fiw_next, &f, wsp->walk_cbdata); 246*2712Snn35248 247*2712Snn35248 fiw->fiw_next = (uintptr_t)f.file_list.list_forw; 248*2712Snn35248 fiw->fiw_count--; 249*2712Snn35248 250*2712Snn35248 return (status); 251*2712Snn35248 } 252*2712Snn35248 253*2712Snn35248 static void 254*2712Snn35248 pr_file_info_walk_fini(mdb_walk_state_t *wsp) 255*2712Snn35248 { 256*2712Snn35248 file_info_walk_t *fiw = wsp->walk_data; 257*2712Snn35248 mdb_free(fiw, sizeof (file_info_walk_t)); 258*2712Snn35248 } 259*2712Snn35248 260*2712Snn35248 /* 261*2712Snn35248 * ::walk pr_map_info 262*2712Snn35248 * 263*2712Snn35248 * Given a ps_prochandle_t, walk all its map_info_t structures. 264*2712Snn35248 */ 265*2712Snn35248 typedef struct { 266*2712Snn35248 uintptr_t miw_next; 267*2712Snn35248 int miw_count; 268*2712Snn35248 int miw_current; 269*2712Snn35248 } map_info_walk_t; 270*2712Snn35248 271*2712Snn35248 static int 272*2712Snn35248 pr_map_info_walk_init(mdb_walk_state_t *wsp) 273*2712Snn35248 { 274*2712Snn35248 ps_prochandle_t psp; 275*2712Snn35248 map_info_walk_t *miw; 276*2712Snn35248 277*2712Snn35248 if (wsp->walk_addr == NULL) { 278*2712Snn35248 mdb_warn("pr_map_info doesn't support global walks\n"); 279*2712Snn35248 return (WALK_ERR); 280*2712Snn35248 } 281*2712Snn35248 282*2712Snn35248 if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) { 283*2712Snn35248 mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr); 284*2712Snn35248 return (WALK_ERR); 285*2712Snn35248 } 286*2712Snn35248 287*2712Snn35248 miw = mdb_alloc(sizeof (map_info_walk_t), UM_SLEEP); 288*2712Snn35248 289*2712Snn35248 miw->miw_next = (uintptr_t)psp.mappings; 290*2712Snn35248 miw->miw_count = psp.map_count; 291*2712Snn35248 miw->miw_current = 0; 292*2712Snn35248 wsp->walk_data = miw; 293*2712Snn35248 294*2712Snn35248 return (WALK_NEXT); 295*2712Snn35248 } 296*2712Snn35248 297*2712Snn35248 static int 298*2712Snn35248 pr_map_info_walk_step(mdb_walk_state_t *wsp) 299*2712Snn35248 { 300*2712Snn35248 map_info_walk_t *miw = wsp->walk_data; 301*2712Snn35248 map_info_t m; 302*2712Snn35248 int status; 303*2712Snn35248 304*2712Snn35248 if (miw->miw_current == miw->miw_count) 305*2712Snn35248 return (WALK_DONE); 306*2712Snn35248 307*2712Snn35248 if (mdb_vread(&m, sizeof (map_info_t), miw->miw_next) == -1) { 308*2712Snn35248 mdb_warn("failed to read map_info_t at %p", miw->miw_next); 309*2712Snn35248 return (WALK_DONE); 310*2712Snn35248 } 311*2712Snn35248 312*2712Snn35248 status = wsp->walk_callback(miw->miw_next, &m, wsp->walk_cbdata); 313*2712Snn35248 314*2712Snn35248 miw->miw_current++; 315*2712Snn35248 miw->miw_next += sizeof (map_info_t); 316*2712Snn35248 317*2712Snn35248 return (status); 318*2712Snn35248 } 319*2712Snn35248 320*2712Snn35248 static void 321*2712Snn35248 pr_map_info_walk_fini(mdb_walk_state_t *wsp) 322*2712Snn35248 { 323*2712Snn35248 map_info_walk_t *miw = wsp->walk_data; 324*2712Snn35248 mdb_free(miw, sizeof (map_info_walk_t)); 325*2712Snn35248 } 326*2712Snn35248 327*2712Snn35248 static const mdb_dcmd_t dcmds[] = { 328*2712Snn35248 { "pr_addr2map", ":addr", "convert an adress into a map_info_t", 329*2712Snn35248 pr_addr2map }, 330*2712Snn35248 { "pr_symtab", ":[-a | -n]", "print the contents of a sym_tbl_t", 331*2712Snn35248 pr_symtab }, 332*2712Snn35248 { NULL } 333*2712Snn35248 }; 334*2712Snn35248 335*2712Snn35248 static const mdb_walker_t walkers[] = { 336*2712Snn35248 { "pr_file_info", "given a ps_prochandle, walk its file_info " 337*2712Snn35248 "structures", pr_file_info_walk_init, pr_file_info_walk_step, 338*2712Snn35248 pr_file_info_walk_fini }, 339*2712Snn35248 { "pr_map_info", "given a ps_prochandle, walk its map_info structures", 340*2712Snn35248 pr_map_info_walk_init, pr_map_info_walk_step, 341*2712Snn35248 pr_map_info_walk_fini }, 342*2712Snn35248 { NULL } 343*2712Snn35248 }; 344*2712Snn35248 345*2712Snn35248 static const mdb_modinfo_t modinfo = { 346*2712Snn35248 MDB_API_VERSION, dcmds, walkers 347*2712Snn35248 }; 348*2712Snn35248 349*2712Snn35248 const mdb_modinfo_t * 350*2712Snn35248 _mdb_init(void) 351*2712Snn35248 { 352*2712Snn35248 return (&modinfo); 353*2712Snn35248 } 354