Path: blob/main/cddl/contrib/opensolaris/cmd/lockstat/sym.c
39488 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License, Version 1.0 only5* (the "License"). You may not use this file except in compliance6* with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or http://www.opensolaris.org/os/licensing.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright (c) 1997-1999 by Sun Microsystems, Inc.23* All rights reserved.24*/2526#pragma ident "%Z%%M% %I% %E% SMI"2728#include <stdio.h>29#include <fcntl.h>30#include <ctype.h>31#include <string.h>32#include <signal.h>33#include <errno.h>34#include <stdlib.h>35#include <stdarg.h>36#include <unistd.h>37#include <limits.h>38#include <sys/types.h>39#include <sys/stat.h>4041#include <libelf.h>42#include <link.h>43#include <elf.h>44#include <gelf.h>45#ifdef illumos46#include <sys/machelf.h>4748#include <kstat.h>49#else50#include <sys/elf.h>51#include <sys/param.h>52#include <sys/module.h>53#include <sys/linker.h>54#endif55#include <sys/cpuvar.h>5657typedef struct syment {58uintptr_t addr;59char *name;60size_t size;61} syment_t;6263static syment_t *symbol_table;64static int nsyms, maxsyms;65static char maxsymname[64];6667#ifdef illumos68#ifdef _ELF6469#define elf_getshdr elf64_getshdr70#else71#define elf_getshdr elf32_getshdr72#endif73#endif7475static void76add_symbol(char *name, uintptr_t addr, size_t size)77{78syment_t *sep;7980if (nsyms >= maxsyms) {81maxsyms += 10000;82symbol_table = realloc(symbol_table, maxsyms * sizeof (*sep));83if (symbol_table == NULL) {84(void) fprintf(stderr, "can't allocate symbol table\n");85exit(3);86}87}88sep = &symbol_table[nsyms++];8990sep->name = name;91sep->addr = addr;92sep->size = size;93}9495static void96remove_symbol(uintptr_t addr)97{98int i;99syment_t *sep = symbol_table;100101for (i = 0; i < nsyms; i++, sep++)102if (sep->addr == addr)103sep->addr = 0;104}105106#ifdef illumos107static void108fake_up_certain_popular_kernel_symbols(void)109{110kstat_ctl_t *kc;111kstat_t *ksp;112char *name;113114if ((kc = kstat_open()) == NULL)115return;116117for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {118if (strcmp(ksp->ks_module, "cpu_info") == 0) {119if ((name = malloc(20)) == NULL)120break;121/*122* For consistency, keep cpu[0] and toss cpu0123* or any other such symbols.124*/125if (ksp->ks_instance == 0)126remove_symbol((uintptr_t)ksp->ks_private);127(void) sprintf(name, "cpu[%d]", ksp->ks_instance);128add_symbol(name, (uintptr_t)ksp->ks_private,129sizeof (struct cpu));130}131}132(void) kstat_close(kc);133}134#else /* !illumos */135static void136fake_up_certain_popular_kernel_symbols(void)137{138char *name;139uintptr_t addr;140int i;141142/* Good for up to 256 CPUs */143for(i=0; i < 256; i++) {144if ((name = malloc(20)) == NULL)145break;146(void) sprintf(name, "cpu[%d]", i);147addr = 0x01000000 + (i << 16);148add_symbol(name, addr, sizeof (uintptr_t));149}150}151#endif /* illumos */152153static int154symcmp(const void *p1, const void *p2)155{156uintptr_t a1 = ((syment_t *)p1)->addr;157uintptr_t a2 = ((syment_t *)p2)->addr;158159if (a1 < a2)160return (-1);161if (a1 > a2)162return (1);163return (0);164}165166int167symtab_init(void)168{169Elf *elf;170Elf_Scn *scn = NULL;171GElf_Sym *symtab, *symp, *lastsym;172char *strtab;173uint_t cnt;174int fd;175int i;176int strindex = -1;177178#ifndef illumos179if ((fd = open("/dev/ksyms", O_RDONLY)) == -1) {180if (errno == ENOENT && modfind("ksyms") == -1) {181kldload("ksyms");182fd = open("/dev/ksyms", O_RDONLY);183}184if (fd == -1)185return (-1);186}187#else188if ((fd = open("/dev/ksyms", O_RDONLY)) == -1)189return (-1);190#endif191192(void) elf_version(EV_CURRENT);193194elf = elf_begin(fd, ELF_C_READ, NULL);195for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {196GElf_Shdr shdr;197(void) gelf_getshdr(scn, &shdr);198if (shdr.sh_type == SHT_SYMTAB) {199symtab = (GElf_Sym *)elf_getdata(scn, NULL)->d_buf;200nsyms = shdr.sh_size / shdr.sh_entsize;201strindex = shdr.sh_link;202}203}204205for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {206if (cnt == strindex)207strtab = (char *)elf_getdata(scn, NULL)->d_buf;208}209210lastsym = symtab + nsyms;211nsyms = 0;212for (symp = symtab; symp < lastsym; symp++)213if ((uint_t)ELF32_ST_TYPE(symp->st_info) <= STT_FUNC &&214symp->st_size != 0)215add_symbol(symp->st_name + strtab,216(uintptr_t)symp->st_value, (size_t)symp->st_size);217218fake_up_certain_popular_kernel_symbols();219(void) sprintf(maxsymname, "0x%lx", ULONG_MAX);220add_symbol(maxsymname, ULONG_MAX, 1);221222qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);223224/*225* Destroy all duplicate symbols, then sort it again.226*/227for (i = 0; i < nsyms - 1; i++)228if (symbol_table[i].addr == symbol_table[i + 1].addr)229symbol_table[i].addr = 0;230231qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);232233while (symbol_table[1].addr == 0) {234symbol_table++;235nsyms--;236}237symbol_table[0].name = "(usermode)";238symbol_table[0].addr = 0;239symbol_table[0].size = 1;240241close(fd);242return (0);243}244245char *246addr_to_sym(uintptr_t addr, uintptr_t *offset, size_t *sizep)247{248int lo = 0;249int hi = nsyms - 1;250int mid;251syment_t *sep;252253while (hi - lo > 1) {254mid = (lo + hi) / 2;255if (addr >= symbol_table[mid].addr) {256lo = mid;257} else {258hi = mid;259}260}261sep = &symbol_table[lo];262*offset = addr - sep->addr;263*sizep = sep->size;264return (sep->name);265}266267uintptr_t268sym_to_addr(char *name)269{270int i;271syment_t *sep = symbol_table;272273for (i = 0; i < nsyms; i++) {274if (strcmp(name, sep->name) == 0)275return (sep->addr);276sep++;277}278return (0);279}280281size_t282sym_size(char *name)283{284int i;285syment_t *sep = symbol_table;286287for (i = 0; i < nsyms; i++) {288if (strcmp(name, sep->name) == 0)289return (sep->size);290sep++;291}292return (0);293}294295296