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