📄 dt_module.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)dt_module.c 1.8 04/11/22 SMI"#include <sys/types.h>#include <sys/modctl.h>#include <sys/kobj.h>#include <sys/kobj_impl.h>#include <sys/sysmacros.h>#include <sys/elf.h>#include <sys/task.h>#include <unistd.h>#include <project.h>#include <strings.h>#include <stdlib.h>#include <libelf.h>#include <limits.h>#include <assert.h>#include <errno.h>#include <alloca.h>#define _POSIX_PTHREAD_SEMANTICS#include <dirent.h>#undef _POSIX_PTHREAD_SEMANTICS#include <dt_strtab.h>#include <dt_module.h>#include <dt_impl.h>static const char *dt_module_strtab; /* active strtab for qsort callbacks */static voiddt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id){ dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree]; uint_t h; assert(dmp->dm_symfree < dmp->dm_nsymelems + 1); dsp->ds_symid = id; h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; dsp->ds_next = dmp->dm_symbuckets[h]; dmp->dm_symbuckets[h] = dmp->dm_symfree++;}static uint_tdt_module_syminit32(dt_module_t *dmp){ const Elf32_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF32_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) asrsv++; /* reserve space in the address map */ dt_module_symhash_insert(dmp, name, i); } return (asrsv);}static uint_tdt_module_syminit64(dt_module_t *dmp){ const Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) asrsv++; /* reserve space in the address map */ dt_module_symhash_insert(dmp, name, i); } return (asrsv);}/* * Sort comparison function for 32-bit symbol address-to-name lookups. We sort * symbols by value. If values are equal, we prefer the symbol that is * non-zero sized, typed, not weak, or lexically first, in that order. */static intdt_module_symcomp32(const void *lp, const void *rp){ Elf32_Sym *lhs = *((Elf32_Sym **)lp); Elf32_Sym *rhs = *((Elf32_Sym **)rp); if (lhs->st_value != rhs->st_value) return (lhs->st_value > rhs->st_value ? 1 : -1); if ((lhs->st_size == 0) != (rhs->st_size == 0)) return (lhs->st_size == 0 ? 1 : -1); if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) != (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE)) return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) != (ELF32_ST_BIND(rhs->st_info) == STB_WEAK)) return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); return (strcmp(dt_module_strtab + lhs->st_name, dt_module_strtab + rhs->st_name));}/* * Sort comparison function for 64-bit symbol address-to-name lookups. We sort * symbols by value. If values are equal, we prefer the symbol that is * non-zero sized, typed, not weak, or lexically first, in that order. */static intdt_module_symcomp64(const void *lp, const void *rp){ Elf64_Sym *lhs = *((Elf64_Sym **)lp); Elf64_Sym *rhs = *((Elf64_Sym **)rp); if (lhs->st_value != rhs->st_value) return (lhs->st_value > rhs->st_value ? 1 : -1); if ((lhs->st_size == 0) != (rhs->st_size == 0)) return (lhs->st_size == 0 ? 1 : -1); if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); return (strcmp(dt_module_strtab + lhs->st_name, dt_module_strtab + rhs->st_name));}static voiddt_module_symsort32(dt_module_t *dmp){ Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data; Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap; const dt_sym_t *dsp = dmp->dm_symchains + 1; uint_t i, n = dmp->dm_symfree; for (i = 1; i < n; i++, dsp++) { Elf32_Sym *sym = symtab + dsp->ds_symid; if (sym->st_value != 0 && (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) *sympp++ = sym; } dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap); assert(dmp->dm_aslen <= dmp->dm_asrsv); dt_module_strtab = dmp->dm_strtab.cts_data; qsort(dmp->dm_asmap, dmp->dm_aslen, sizeof (Elf32_Sym *), dt_module_symcomp32); dt_module_strtab = NULL;}static voiddt_module_symsort64(dt_module_t *dmp){ Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data; Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap; const dt_sym_t *dsp = dmp->dm_symchains + 1; uint_t i, n = dmp->dm_symfree; for (i = 1; i < n; i++, dsp++) { Elf64_Sym *sym = symtab + dsp->ds_symid; if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) *sympp++ = sym; } dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap); assert(dmp->dm_aslen <= dmp->dm_asrsv); dt_module_strtab = dmp->dm_strtab.cts_data; qsort(dmp->dm_asmap, dmp->dm_aslen, sizeof (Elf64_Sym *), dt_module_symcomp64); dt_module_strtab = NULL;}static GElf_Sym *dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst){ if (dst != NULL) { dst->st_name = src->st_name; dst->st_info = src->st_info; dst->st_other = src->st_other; dst->st_shndx = src->st_shndx; dst->st_value = src->st_value; dst->st_size = src->st_size; } return (dst);}static GElf_Sym *dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst){ if (dst != NULL) bcopy(src, dst, sizeof (GElf_Sym)); return (dst);}static GElf_Sym *dt_module_symname32(dt_module_t *dmp, const char *name, GElf_Sym *symp, uint_t *idp){ const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; const char *strtab = dmp->dm_strtab.cts_data; const Elf32_Sym *sym; const dt_sym_t *dsp; uint_t i, h; if (dmp->dm_nsymelems == 0) return (NULL); h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { dsp = &dmp->dm_symchains[i]; sym = symtab + dsp->ds_symid; if (strcmp(name, strtab + sym->st_name) == 0) { if (idp != NULL) *idp = dsp->ds_symid; return (dt_module_symgelf32(sym, symp)); } } return (NULL);}static GElf_Sym *dt_module_symname64(dt_module_t *dmp, const char *name, GElf_Sym *symp, uint_t *idp){ const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; const char *strtab = dmp->dm_strtab.cts_data; const Elf64_Sym *sym; const dt_sym_t *dsp; uint_t i, h; if (dmp->dm_nsymelems == 0) return (NULL); h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { dsp = &dmp->dm_symchains[i]; sym = symtab + dsp->ds_symid; if (strcmp(name, strtab + sym->st_name) == 0) { if (idp != NULL) *idp = dsp->ds_symid; return (dt_module_symgelf64(sym, symp)); } } return (NULL);}static GElf_Sym *dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr, GElf_Sym *symp, uint_t *idp){ const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap; const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; const Elf32_Sym *sym; uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; Elf32_Addr v; if (dmp->dm_aslen == 0) return (NULL); while (hi - lo > 1) { mid = (lo + hi) / 2; if (addr >= asmap[mid]->st_value) lo = mid; else hi = mid; } i = addr < asmap[hi]->st_value ? lo : hi; sym = asmap[i]; v = sym->st_value; /* * If the previous entry has the same value, improve our choice. The * order of equal-valued symbols is determined by the comparison func. */ while (i-- != 0 && asmap[i]->st_value == v) sym = asmap[i]; if (addr - sym->st_value < MAX(sym->st_size, 1)) { if (idp != NULL) *idp = (uint_t)(sym - symtab); return (dt_module_symgelf32(sym, symp)); } return (NULL);}static GElf_Sym *dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr, GElf_Sym *symp, uint_t *idp){ const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap; const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; const Elf64_Sym *sym; uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; Elf64_Addr v; if (dmp->dm_aslen == 0) return (NULL); while (hi - lo > 1) { mid = (lo + hi) / 2; if (addr >= asmap[mid]->st_value) lo = mid; else hi = mid; } i = addr < asmap[hi]->st_value ? lo : hi; sym = asmap[i]; v = sym->st_value; /* * If the previous entry has the same value, improve our choice. The * order of equal-valued symbols is determined by the comparison func. */ while (i-- != 0 && asmap[i]->st_value == v) sym = asmap[i]; if (addr - sym->st_value < MAX(sym->st_size, 1)) { if (idp != NULL) *idp = (uint_t)(sym - symtab); return (dt_module_symgelf64(sym, symp)); } return (NULL);}static const dt_modops_t dt_modops_32 = { dt_module_syminit32, dt_module_symsort32, dt_module_symname32, dt_module_symaddr32};static const dt_modops_t dt_modops_64 = { dt_module_syminit64, dt_module_symsort64, dt_module_symname64, dt_module_symaddr64};dt_module_t *dt_module_create(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); } if ((dmp = malloc(sizeof (dt_module_t))) == NULL) return (NULL); /* caller must handle allocation failure */ bzero(dmp, sizeof (dt_module_t)); (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name)); dt_list_append(&dtp->dt_modlist, dmp); dmp->dm_next = dtp->dt_mods[h]; dtp->dt_mods[h] = dmp; dtp->dt_nmods++; if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) dmp->dm_ops = &dt_modops_64; else dmp->dm_ops = &dt_modops_32; return (dmp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -