📄 dt_module.c
字号:
dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name){ uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0) return (dmp); } return (NULL);}dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp){ dt_module_t *dmp; for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = dt_list_next(dmp)) { if (dmp->dm_ctfp == ctfp) return (dmp); } return (NULL);}static intdt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp){ const char *s; size_t shstrs; GElf_Shdr sh; Elf_Data *dp; Elf_Scn *sp; if (elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) return (dt_set_errno(dtp, EDT_NOTLOADED)); for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) continue; /* skip any malformed sections */ if (sh.sh_type == ctsp->cts_type && sh.sh_entsize == ctsp->cts_entsize && strcmp(s, ctsp->cts_name) == 0) break; /* section matches specification */ } /* * If the section isn't found, return success but leave cts_data set * to NULL and cts_size set to zero for our caller. */ if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL) return (0); ctsp->cts_data = dp->d_buf; ctsp->cts_size = dp->d_size; dt_dprintf("loaded %s [%s] (%lu bytes)\n", dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size); return (0);}intdt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp){ if (dmp->dm_flags & DT_DM_LOADED) return (0); /* module is already loaded */ dmp->dm_ctdata.cts_name = ".SUNW_ctf"; dmp->dm_ctdata.cts_type = SHT_PROGBITS; dmp->dm_ctdata.cts_flags = 0; dmp->dm_ctdata.cts_data = NULL; dmp->dm_ctdata.cts_size = 0; dmp->dm_ctdata.cts_entsize = 0; dmp->dm_ctdata.cts_offset = 0; dmp->dm_symtab.cts_name = ".symtab"; dmp->dm_symtab.cts_type = SHT_SYMTAB; dmp->dm_symtab.cts_flags = 0; dmp->dm_symtab.cts_data = NULL; dmp->dm_symtab.cts_size = 0; dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ? sizeof (Elf64_Sym) : sizeof (Elf32_Sym); dmp->dm_symtab.cts_offset = 0; dmp->dm_strtab.cts_name = ".strtab"; dmp->dm_strtab.cts_type = SHT_STRTAB; dmp->dm_strtab.cts_flags = 0; dmp->dm_strtab.cts_data = NULL; dmp->dm_strtab.cts_size = 0; dmp->dm_strtab.cts_entsize = 0; dmp->dm_strtab.cts_offset = 0; /* * Attempt to load the module's CTF section, symbol table section, and * string table section. Note that modules may not contain CTF data: * this will result in a successful load_sect but data of size zero. * We will then fail if dt_module_getctf() is called, as shown below. */ if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 || dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 || dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) { dt_module_unload(dtp, dmp); return (-1); /* dt_errno is set for us */ } /* * Allocate the hash chains and hash buckets for symbol name lookup. * This is relatively simple since the symbol table is of fixed size * and is known in advance. We allocate one extra element since we * use element indices instead of pointers and zero is our sentinel. */ dmp->dm_nsymelems = dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize; dmp->dm_nsymbuckets = _dtrace_strbuckets; dmp->dm_symfree = 1; /* first free element is index 1 */ dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets); dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1); if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) { dt_module_unload(dtp, dmp); return (dt_set_errno(dtp, EDT_NOMEM)); } bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets); bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1); /* * Iterate over the symbol table data buffer and insert each symbol * name into the name hash if the name and type are valid. Then * allocate the address map, fill it in, and sort it. */ dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp); dt_dprintf("hashed %s [%s] (%u symbols)\n", dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1); if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) { dt_module_unload(dtp, dmp); return (dt_set_errno(dtp, EDT_NOMEM)); } dmp->dm_ops->do_symsort(dmp); dt_dprintf("sorted %s [%s] (%u symbols)\n", dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen); dmp->dm_flags |= DT_DM_LOADED; return (0);}ctf_file_t *dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp){ const char *parent; dt_module_t *pmp; ctf_file_t *pfp; int model; if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0) return (dmp->dm_ctfp); if (dmp->dm_ops == &dt_modops_64) model = CTF_MODEL_LP64; else model = CTF_MODEL_ILP32; /* * If the data model of the module does not match our program data * model, then do not permit CTF from this module to be opened and * returned to the compiler. If we support mixed data models in the * future for combined kernel/user tracing, this can be removed. */ if (dtp->dt_conf.dtc_ctfmodel != model) { (void) dt_set_errno(dtp, EDT_DATAMODEL); return (NULL); } if (dmp->dm_ctdata.cts_size == 0) { (void) dt_set_errno(dtp, EDT_NOCTF); return (NULL); } dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata, &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr); if (dmp->dm_ctfp == NULL || ctf_setmodel(dmp->dm_ctfp, model) != 0) { (void) dt_set_errno(dtp, EDT_CTF); return (NULL); } if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) { if ((pmp = dt_module_create(dtp, parent)) == NULL || (pfp = dt_module_getctf(dtp, pmp)) == NULL) { if (pmp == NULL) (void) dt_set_errno(dtp, EDT_NOMEM); goto err; } if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) { dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp); (void) dt_set_errno(dtp, EDT_CTF); goto err; } } dt_dprintf("loaded CTF container for %s (%p)\n", dmp->dm_name, (void *)dmp->dm_ctfp); return (dmp->dm_ctfp);err: ctf_close(dmp->dm_ctfp); dmp->dm_ctfp = NULL; return (NULL);}/*ARGSUSED*/voiddt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp){ ctf_close(dmp->dm_ctfp); dmp->dm_ctfp = NULL; bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t)); bzero(&dmp->dm_symtab, sizeof (ctf_sect_t)); bzero(&dmp->dm_strtab, sizeof (ctf_sect_t)); if (dmp->dm_symbuckets != NULL) { free(dmp->dm_symbuckets); dmp->dm_symbuckets = NULL; } if (dmp->dm_symchains != NULL) { free(dmp->dm_symchains); dmp->dm_symchains = NULL; } if (dmp->dm_asmap != NULL) { free(dmp->dm_asmap); dmp->dm_asmap = NULL; } dmp->dm_symfree = 0; dmp->dm_nsymbuckets = 0; dmp->dm_nsymelems = 0; dmp->dm_asrsv = 0; dmp->dm_aslen = 0; dmp->dm_text_va = NULL; dmp->dm_text_size = 0; dmp->dm_data_va = NULL; dmp->dm_data_size = 0; dmp->dm_bss_va = NULL; dmp->dm_bss_size = 0; if (dmp->dm_extern != NULL) { dt_idhash_destroy(dmp->dm_extern); dmp->dm_extern = NULL; } (void) elf_end(dmp->dm_elf); dmp->dm_elf = NULL; dmp->dm_flags &= ~DT_DM_LOADED;}voiddt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp){ dt_list_delete(&dtp->dt_modlist, dmp); assert(dtp->dt_nmods != 0); dtp->dt_nmods--; dt_module_unload(dtp, dmp); free(dmp);}/* * Insert a new external symbol reference into the specified module. The new * symbol will be marked as undefined and is assigned a symbol index beyond * any existing cached symbols from this module. We use the ident's di_data * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol. */dt_ident_t *dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name, const dtrace_typeinfo_t *tip){ dtrace_syminfo_t *sip; dt_ident_t *idp; uint_t id; if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create( "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) { (void) dt_set_errno(dtp, EDT_SYMOFLOW); return (NULL); } if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id, _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen); if (idp == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); free(sip); return (NULL); } sip->dts_object = dmp->dm_name; sip->dts_name = idp->di_name; sip->dts_id = idp->di_id; idp->di_data = sip; idp->di_ctfp = tip->dtt_ctfp; idp->di_type = tip->dtt_type; return (idp);}const char *dt_module_modelname(dt_module_t *dmp){ if (dmp->dm_ops == &dt_modops_64) return ("64-bit"); else return ("32-bit");}/* * Update our module cache by adding an entry for the specified module 'name'. * We create the dt_module_t and populate it using /system/object/<name>/. */static voiddt_module_update(dtrace_hdl_t *dtp, const char *name){ char fname[MAXPATHLEN]; struct stat64 st; int fd, err, bits; dt_module_t *dmp; const char *s; size_t shstrs; GElf_Shdr sh; Elf_Data *dp; Elf_Scn *sp; (void) snprintf(fname, sizeof (fname), "%s/%s/object", OBJFS_ROOT, name); if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 || (dmp = dt_module_create(dtp, name)) == NULL) { dt_dprintf("failed to open %s: %s\n", fname, strerror(errno)); (void) close(fd); return; } /* * Since the module can unload out from under us (and /system/object * will return ENOENT), tell libelf to cook the entire file now and * then close the underlying file descriptor immediately. If this * succeeds, we know that we can continue safely using dmp->dm_elf. */ dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL); err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD); (void) close(fd); if (dmp->dm_elf == NULL || err == -1 || elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) { dt_dprintf("failed to load %s: %s\n", fname, elf_errmsg(elf_errno())); dt_module_destroy(dtp, dmp); return; } switch (gelf_getclass(dmp->dm_elf)) { case ELFCLASS32: dmp->dm_ops = &dt_modops_32; bits = 32; break; case ELFCLASS64: dmp->dm_ops = &dt_modops_64; bits = 64; break; default: dt_dprintf("failed to load %s: unknown ELF class\n", fname); dt_module_destroy(dtp, dmp); return; } /* * Iterate over the section headers locating various sections of * interest and use their attributes to flesh out the dt_module_t. */ for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) continue; /* skip any malformed sections */ if (strcmp(s, ".text") == 0) { dmp->dm_text_size = sh.sh_size; dmp->dm_text_va = sh.sh_addr; } else if (strcmp(s, ".data") == 0) { dmp->dm_data_size = sh.sh_size; dmp->dm_data_va = sh.sh_addr; } else if (strcmp(s, ".bss") == 0) { dmp->dm_bss_size = sh.sh_size; dmp->dm_bss_va = sh.sh_addr; } else if (strcmp(s, ".info") == 0 && (dp = elf_getdata(sp, NULL)) != NULL) { bcopy(dp->d_buf, &dmp->dm_info, MIN(sh.sh_size, sizeof (dmp->dm_info))); } else if (strcmp(s, ".filename") == 0 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -