1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/machelf.h> 30 #include <sys/modctl.h> 31 #include <sys/kobj.h> 32 33 #include <mdb/mdb_modapi.h> 34 35 static uintptr_t module_head; /* Head of kernel modctl list */ 36 37 struct modctl_walk_data { 38 uintptr_t mwd_head; 39 struct modctl mwd_modctl; 40 }; 41 42 static int 43 modctl_walk_init(mdb_walk_state_t *wsp) 44 { 45 struct modctl_walk_data *mwd = mdb_alloc( 46 sizeof (struct modctl_walk_data), UM_SLEEP); 47 48 mwd->mwd_head = (wsp->walk_addr == NULL ? module_head : wsp->walk_addr); 49 wsp->walk_data = mwd; 50 wsp->walk_addr = NULL; 51 52 return (WALK_NEXT); 53 } 54 55 static int 56 modctl_walk_step(mdb_walk_state_t *wsp) 57 { 58 struct modctl_walk_data *mwd = wsp->walk_data; 59 int status; 60 61 if (wsp->walk_addr == mwd->mwd_head) 62 return (WALK_DONE); 63 64 if (wsp->walk_addr == NULL) 65 wsp->walk_addr = mwd->mwd_head; 66 67 if (mdb_vread(&mwd->mwd_modctl, sizeof (struct modctl), 68 wsp->walk_addr) == -1) { 69 mdb_warn("failed to read modctl at %p", wsp->walk_addr); 70 return (WALK_ERR); 71 } 72 73 status = wsp->walk_callback(wsp->walk_addr, &mwd->mwd_modctl, 74 wsp->walk_cbdata); 75 76 wsp->walk_addr = (uintptr_t)mwd->mwd_modctl.mod_next; 77 78 return (status); 79 } 80 81 static void 82 modctl_walk_fini(mdb_walk_state_t *wsp) 83 { 84 mdb_free(wsp->walk_data, sizeof (struct modctl_walk_data)); 85 } 86 87 /*ARGSUSED*/ 88 static int 89 modctl_format(uintptr_t addr, const void *data, void *private) 90 { 91 const struct modctl *mcp = (const struct modctl *)data; 92 char name[MAXPATHLEN], bits[6], *bp = &bits[0]; 93 94 if (mdb_readstr(name, sizeof (name), 95 (uintptr_t)mcp->mod_filename) == -1) 96 (void) strcpy(name, "???"); 97 98 if (mcp->mod_busy) 99 *bp++ = 'b'; 100 if (mcp->mod_want) 101 *bp++ = 'w'; 102 if (mcp->mod_prim) 103 *bp++ = 'p'; 104 if (mcp->mod_loaded) 105 *bp++ = 'l'; 106 if (mcp->mod_installed) 107 *bp++ = 'i'; 108 *bp = '\0'; 109 110 mdb_printf("%?p %?p %6s 0x%02x %3d %s\n", 111 (uintptr_t)addr, (uintptr_t)mcp->mod_mp, bits, mcp->mod_loadflags, 112 mcp->mod_ref, name); 113 114 return (WALK_NEXT); 115 } 116 117 /*ARGSUSED*/ 118 static int 119 modctls(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 120 { 121 if (argc != 0) 122 return (DCMD_USAGE); 123 124 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 125 mdb_printf("%<u>%?s %?s %6s %4s %3s %s%</u>\n", 126 "MODCTL", "MODULE", "BITS", "FLAGS", "REF", "FILE"); 127 } 128 129 if (flags & DCMD_ADDRSPEC) { 130 struct modctl mc; 131 132 (void) mdb_vread(&mc, sizeof (mc), addr); 133 return (modctl_format(addr, &mc, NULL)); 134 } 135 136 if (mdb_walk("modctl", modctl_format, NULL) == -1) 137 return (DCMD_ERR); 138 139 return (DCMD_OK); 140 } 141 142 static void 143 dump_ehdr(const Ehdr *ehdr) 144 { 145 mdb_printf("\nELF Header\n"); 146 147 mdb_printf(" ei_magic: { 0x%02x, %c, %c, %c }\n", 148 ehdr->e_ident[EI_MAG0], ehdr->e_ident[EI_MAG1], 149 ehdr->e_ident[EI_MAG2], ehdr->e_ident[EI_MAG3]); 150 151 mdb_printf(" ei_class: %-18u ei_data: %-16u\n", 152 ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); 153 154 mdb_printf(" e_machine: %-18hu e_version: %-16u\n", 155 ehdr->e_machine, ehdr->e_version); 156 157 mdb_printf(" e_type: %-18hu\n", ehdr->e_type); 158 mdb_printf(" e_flags: %-18u\n", ehdr->e_flags); 159 160 mdb_printf(" e_entry: 0x%16lx e_ehsize: %8hu e_shstrndx: %hu\n", 161 ehdr->e_entry, ehdr->e_ehsize, ehdr->e_shstrndx); 162 163 mdb_printf(" e_shoff: 0x%16lx e_shentsize: %8hu e_shnum: %hu\n", 164 ehdr->e_shoff, ehdr->e_shentsize, ehdr->e_shnum); 165 166 mdb_printf(" e_phoff: 0x%16lx e_phentsize: %8hu e_phnum: %hu\n", 167 ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum); 168 } 169 170 static void 171 dump_shdr(const Shdr *shdr, int i) 172 { 173 static const mdb_bitmask_t sh_type_masks[] = { 174 { "SHT_NULL", 0xffffffff, SHT_NULL }, 175 { "SHT_PROGBITS", 0xffffffff, SHT_PROGBITS }, 176 { "SHT_SYMTAB", 0xffffffff, SHT_SYMTAB }, 177 { "SHT_STRTAB", 0xffffffff, SHT_STRTAB }, 178 { "SHT_RELA", 0xffffffff, SHT_RELA }, 179 { "SHT_HASH", 0xffffffff, SHT_HASH }, 180 { "SHT_DYNAMIC", 0xffffffff, SHT_DYNAMIC }, 181 { "SHT_NOTE", 0xffffffff, SHT_NOTE }, 182 { "SHT_NOBITS", 0xffffffff, SHT_NOBITS }, 183 { "SHT_REL", 0xffffffff, SHT_REL }, 184 { "SHT_SHLIB", 0xffffffff, SHT_SHLIB }, 185 { "SHT_DYNSYM", 0xffffffff, SHT_DYNSYM }, 186 { "SHT_LOSUNW", 0xffffffff, SHT_LOSUNW }, 187 { "SHT_SUNW_COMDAT", 0xffffffff, SHT_SUNW_COMDAT }, 188 { "SHT_SUNW_syminfo", 0xffffffff, SHT_SUNW_syminfo }, 189 { "SHT_SUNW_verdef", 0xffffffff, SHT_SUNW_verdef }, 190 { "SHT_SUNW_verneed", 0xffffffff, SHT_SUNW_verneed }, 191 { "SHT_SUNW_versym", 0xffffffff, SHT_SUNW_versym }, 192 { "SHT_HISUNW", 0xffffffff, SHT_HISUNW }, 193 { "SHT_LOPROC", 0xffffffff, SHT_LOPROC }, 194 { "SHT_HIPROC", 0xffffffff, SHT_HIPROC }, 195 { "SHT_LOUSER", 0xffffffff, SHT_LOUSER }, 196 { "SHT_HIUSER", 0xffffffff, SHT_HIUSER }, 197 { NULL, 0, 0 } 198 }; 199 200 static const mdb_bitmask_t sh_flag_masks[] = { 201 { "SHF_WRITE", SHF_WRITE, SHF_WRITE }, 202 { "SHF_ALLOC", SHF_ALLOC, SHF_ALLOC }, 203 { "SHF_EXECINSTR", SHF_EXECINSTR, SHF_EXECINSTR }, 204 { "SHF_MASKPROC", SHF_MASKPROC, SHF_MASKPROC }, 205 { NULL, 0, 0 } 206 }; 207 208 mdb_printf("\nSection Header[%d]:\n", i); 209 210 mdb_printf(" sh_addr: 0x%-16lx sh_flags: [ %#lb ]\n", 211 shdr->sh_addr, shdr->sh_flags, sh_flag_masks); 212 213 mdb_printf(" sh_size: 0x%-16lx sh_type: [ %#lb ]\n", 214 shdr->sh_size, shdr->sh_type, sh_type_masks); 215 216 mdb_printf(" sh_offset: 0x%-16lx sh_entsize: 0x%lx\n", 217 shdr->sh_offset, shdr->sh_entsize); 218 219 mdb_printf(" sh_link: 0x%-16lx sh_info: 0x%lx\n", 220 shdr->sh_link, shdr->sh_info); 221 222 mdb_printf(" sh_addralign: 0x%-16lx\n", shdr->sh_addralign); 223 } 224 225 /*ARGSUSED*/ 226 static int 227 modhdrs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 228 { 229 struct modctl ctl; 230 struct module mod; 231 Shdr *shdrs; 232 233 size_t nbytes; 234 int i; 235 236 if (!(flags & DCMD_ADDRSPEC)) { 237 mdb_warn("expected address of struct modctl before ::\n"); 238 return (DCMD_USAGE); 239 } 240 241 if (argc != 0) 242 return (DCMD_USAGE); 243 244 mdb_vread(&ctl, sizeof (struct modctl), addr); 245 mdb_vread(&mod, sizeof (struct module), (uintptr_t)ctl.mod_mp); 246 dump_ehdr(&mod.hdr); 247 248 nbytes = sizeof (Shdr) * mod.hdr.e_shnum; 249 shdrs = mdb_alloc(nbytes, UM_SLEEP | UM_GC); 250 mdb_vread(shdrs, nbytes, (uintptr_t)mod.shdrs); 251 252 for (i = 0; i < mod.hdr.e_shnum; i++) 253 dump_shdr(&shdrs[i], i); 254 255 return (DCMD_OK); 256 } 257 258 /*ARGSUSED*/ 259 static int 260 modinfo_format(uintptr_t addr, const void *data, void *private) 261 { 262 const struct modctl *mcp = (const struct modctl *)data; 263 264 struct modlinkage linkage; 265 struct modlmisc lmisc; 266 struct module mod; 267 268 char info[MODMAXLINKINFOLEN]; 269 char name[MODMAXNAMELEN]; 270 271 mod.text_size = 0; 272 mod.data_size = 0; 273 mod.text = NULL; 274 275 linkage.ml_rev = 0; 276 277 info[0] = '\0'; 278 279 if (mcp->mod_mp != NULL) 280 (void) mdb_vread(&mod, sizeof (mod), (uintptr_t)mcp->mod_mp); 281 282 if (mcp->mod_linkage != NULL) { 283 (void) mdb_vread(&linkage, sizeof (linkage), 284 (uintptr_t)mcp->mod_linkage); 285 286 if (linkage.ml_linkage[0] != NULL) { 287 (void) mdb_vread(&lmisc, sizeof (lmisc), 288 (uintptr_t)linkage.ml_linkage[0]); 289 mdb_readstr(info, sizeof (info), 290 (uintptr_t)lmisc.misc_linkinfo); 291 } 292 } 293 294 if (mdb_readstr(name, sizeof (name), (uintptr_t)mcp->mod_modname) == -1) 295 (void) strcpy(name, "???"); 296 297 mdb_printf("%3d %?p %8lx %3d %s (%s)\n", 298 mcp->mod_id, mod.text, mod.text_size + mod.data_size, 299 linkage.ml_rev, name, info[0] != '\0' ? info : "?"); 300 301 return (WALK_NEXT); 302 } 303 304 /*ARGSUSED*/ 305 static int 306 modinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 307 { 308 if (argc != 0) 309 return (DCMD_USAGE); 310 311 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 312 mdb_printf("%<u>%3s %?s %8s %3s %s%</u>\n", 313 "ID", "LOADADDR", "SIZE", "REV", "MODULE NAME"); 314 } 315 316 if (flags & DCMD_ADDRSPEC) { 317 struct modctl mc; 318 319 (void) mdb_vread(&mc, sizeof (mc), addr); 320 return (modinfo_format(addr, &mc, NULL)); 321 } 322 323 if (mdb_walk("modctl", modinfo_format, NULL) == -1) 324 return (DCMD_ERR); 325 326 return (DCMD_OK); 327 } 328 329 /*ARGSUSED*/ 330 static int 331 ctfinfo_format(uintptr_t addr, const struct modctl *mcp, void *private) 332 { 333 char name[MODMAXNAMELEN]; 334 struct module mod; 335 336 if (mcp->mod_mp == NULL) 337 return (WALK_NEXT); /* module is not loaded */ 338 339 if (mdb_vread(&mod, sizeof (mod), (uintptr_t)mcp->mod_mp) == -1) { 340 mdb_warn("failed to read module at %p for modctl %p\n", 341 mcp->mod_mp, addr); 342 return (WALK_NEXT); 343 } 344 345 if (mdb_readstr(name, sizeof (name), (uintptr_t)mcp->mod_modname) == -1) 346 (void) mdb_snprintf(name, sizeof (name), "%a", mcp->mod_mp); 347 348 mdb_printf("%-30s %?p %lu\n", name, mod.ctfdata, (ulong_t)mod.ctfsize); 349 return (WALK_NEXT); 350 } 351 352 /*ARGSUSED*/ 353 static int 354 ctfinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 355 { 356 if ((flags & DCMD_ADDRSPEC) || argc != 0) 357 return (DCMD_USAGE); 358 359 mdb_printf("%<u>%-30s %?s %s%</u>\n", "MODULE", "CTFDATA", "CTFSIZE"); 360 if (mdb_walk("modctl", (mdb_walk_cb_t)ctfinfo_format, NULL) == -1) 361 return (DCMD_ERR); 362 363 return (DCMD_OK); 364 } 365 366 static const mdb_dcmd_t dcmds[] = { 367 { "modctl", NULL, "list modctl structures", modctls }, 368 { "modhdrs", ":", "given modctl, dump module ehdr and shdrs", modhdrs }, 369 { "modinfo", NULL, "list module information", modinfo }, 370 { "ctfinfo", NULL, "list module CTF information", ctfinfo }, 371 { NULL } 372 }; 373 374 static const mdb_walker_t walkers[] = { 375 { "modctl", "list of modctl structures", 376 modctl_walk_init, modctl_walk_step, modctl_walk_fini }, 377 { NULL } 378 }; 379 380 static const mdb_modinfo_t krtld_modinfo = { MDB_API_VERSION, dcmds, walkers }; 381 382 const mdb_modinfo_t * 383 _mdb_init(void) 384 { 385 GElf_Sym sym; 386 387 if (mdb_lookup_by_name("modules", &sym) == -1) { 388 mdb_warn("failed to lookup 'modules'"); 389 return (NULL); 390 } 391 392 module_head = (uintptr_t)sym.st_value; 393 return (&krtld_modinfo); 394 } 395