Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/make/non-build-utils/reorder/tools/mcount.c
32285 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdio.h>26#include <sys/mman.h>27#include <dlfcn.h>28#include <libelf.h>29#include <strings.h>30#include <fcntl.h>31#include <sys/param.h>32#include <stdlib.h>33#include <thread.h>34#include <synch.h>35#include <stdarg.h>36#include <unistd.h>3738#define TRUE 139#define FALSE 04041/* 32/64 bit build issues. */4243#ifdef _LP6444#define ElfXX_Sym Elf64_Sym45#define ElfXX_Ehdr Elf64_Ehdr46#define ElfXX_Shdr Elf64_Shdr47#define elfXX_getehdr elf64_getehdr48#define ElfXX_Addr Elf64_Addr49#define ELFXX_ST_TYPE ELF64_ST_TYPE50#define ELFXX_ST_BIND ELF64_ST_BIND51#define elfXX_getshdr elf64_getshdr52#else53#define ElfXX_Sym Elf32_Sym54#define ElfXX_Ehdr Elf32_Ehdr55#define ElfXX_Shdr Elf32_Shdr56#define elfXX_getehdr elf32_getehdr57#define ElfXX_Addr Elf32_Addr58#define ELFXX_ST_TYPE ELF32_ST_TYPE59#define ELFXX_ST_BIND ELF32_ST_BIND60#define elfXX_getshdr elf32_getshdr61#endif6263extern void *_getReturnAddr(void);64656667typedef struct StabEntry {68unsigned n_strx;69unsigned char n_type;70char n_other;71short n_desc;72unsigned n_value;73} StabEntry;747576typedef struct SymChain {77struct SymChain *next;78ElfXX_Sym *sym;79} SymChain;808182typedef struct ObjFileList {83struct ObjFileList *next;84const char *objFileName;85int nameLen;86} ObjFileList;878889typedef struct ElfInfo {90const char *fullName;91const char *baseName;92FILE *outFile;93int fd;94Elf *elf;95Elf_Data *sectionStringData;96Elf_Data *symData;97Elf_Data *symStringData;98int symCount;99SymChain *symChainHead;100Elf_Data *stabData;101Elf_Data *stabStringData;102int stabCount;103ObjFileList *objFileList;104} ElfInfo;105106107108#define COUNT_BUF_SIZE (16*1024*1024)109110#define ENTRY_CHAIN_BUCKETS 4999111112static int *countBuf;113static void *textOffset;114static const char *libFileName;115116117118static void fail(const char *err, ...)119{120va_list ap;121va_start(ap, err);122vfprintf(stderr, err, ap);123fflush(stderr);124va_end(ap);125}126127128129static const char *getSymString(ElfInfo *elfInfo, int index)130{131return (const char *)elfInfo->symStringData->d_buf + index;132}133134135static const char *getStabString(ElfInfo *elfInfo, int index)136{137return (const char *)elfInfo->stabStringData->d_buf + index;138}139140141static const char *getSectionString(ElfInfo *elfInfo, int index)142{143return (const char *)elfInfo->sectionStringData->d_buf + index;144}145146147static const char *makeObjFileList(ElfInfo *elfInfo)148{149int i;150const char *file;151unsigned offset, lastOffset;152ObjFileList *objFileList;153154file = NULL;155offset = lastOffset = 0;156for (i = 0; i < elfInfo->stabCount; ++i) {157StabEntry *stab = ((StabEntry *)elfInfo->stabData->d_buf) + i;158159if (stab->n_type == 0 /* N_UNDEF */) {160offset = lastOffset;161lastOffset += stab-> n_value;162}163else if (stab->n_type == 0x38 /* N_OBJ */) {164file = getStabString(elfInfo, stab->n_strx + offset);165objFileList = (ObjFileList *)malloc(sizeof (ObjFileList));166objFileList->objFileName = file;167/*fprintf(stderr,"new obj file %s.\n", file);*/168objFileList->nameLen = strlen(file);169objFileList->next = elfInfo->objFileList;170elfInfo->objFileList = objFileList;171}172}173return NULL;174}175176177static ElfInfo *createElfInfo(const char *fullName)178{179ElfInfo *elfInfo;180ElfXX_Ehdr *ehdr;181Elf_Scn *sectionStringSection;182Elf_Scn *stringSection;183Elf_Scn *symSection;184ElfXX_Shdr *symHeader;185Elf_Scn *stabSection;186ElfXX_Shdr *stabHeader;187ElfXX_Shdr *stringHeader;188Elf *elf;189const char *p;190191/*fprintf(stderr, "# mapfile info for %s.\n", fullName);*/192elfInfo = (ElfInfo *)malloc(sizeof (ElfInfo));193memset(elfInfo, 0, sizeof (ElfInfo));194elfInfo->fullName = strdup(fullName);195p = rindex(elfInfo->fullName, '/');196elfInfo->baseName = (p == NULL) ? elfInfo->fullName : p + 1;197198/* Open the ELF file. Get section headers. */199200elf_version(EV_CURRENT);201elfInfo->fd = open(fullName, O_RDONLY);202if (elfInfo->fd < 0)203fail("Unable to open ELF file %s.\n", fullName);204elf = elf_begin(elfInfo->fd, ELF_C_READ, (Elf *)0);205if (elf == NULL)206fail("elf_begin failed.\n");207ehdr = elfXX_getehdr(elf);208sectionStringSection = elf_getscn(elf, ehdr->e_shstrndx);209elfInfo->sectionStringData = elf_getdata(sectionStringSection, NULL);210211/* Find the symbol table section. */212213symSection = NULL;214while ((symSection = elf_nextscn(elf, symSection)) != NULL) {215symHeader = elfXX_getshdr(symSection);216p = getSectionString(elfInfo, symHeader->sh_name);217if (strcmp(p, ".symtab") == 0)218break;219}220if (symSection == NULL)221fail("Unable to find symbol table.\n");222223elfInfo->symData = elf_getdata(symSection, NULL);224elfInfo->symCount = elfInfo->symData->d_size / sizeof (ElfXX_Sym);225226/* Find the string section. */227228stringSection = NULL;229while ((stringSection = elf_nextscn(elf, stringSection)) != NULL) {230stringHeader = elfXX_getshdr(stringSection);231p = getSectionString(elfInfo, stringHeader->sh_name);232if (strcmp(p, ".strtab") == 0)233break;234}235if (stringSection == NULL)236fail("Unable to find string table.\n");237238elfInfo->symStringData = elf_getdata(stringSection, NULL);239elfInfo->symChainHead = NULL;240241/* Find the stab section. */242243stabSection = NULL;244while ((stabSection = elf_nextscn(elf, stabSection)) != NULL) {245stabHeader = elfXX_getshdr(stabSection);246p = getSectionString(elfInfo, stabHeader->sh_name);247if (strcmp(p, ".stab.index") == 0)248break;249}250if (stabSection == NULL)251fail("Unable to find .stab.index.\n");252253elfInfo->stabData = elf_getdata(stabSection, NULL);254elfInfo->stabCount = elfInfo->stabData->d_size / sizeof (StabEntry);255256/* Find the string section. */257258stringSection = NULL;259while ((stringSection = elf_nextscn(elf, stringSection)) != NULL) {260stringHeader = elfXX_getshdr(stringSection);261p = getSectionString(elfInfo, stringHeader->sh_name);262if (strcmp(p, ".stab.indexstr") == 0)263break;264}265if (stringSection == NULL)266fail("Unable to find .stab.indexstr table.\n");267268elfInfo->stabStringData = elf_getdata(stringSection, NULL);269makeObjFileList(elfInfo);270271return elfInfo;272}273274275static const char *identifyFile(ElfInfo *elfInfo, const char *name)276{277int i;278const char *file;279const char *sourceFile;280unsigned offset, lastOffset;281const char *lastOptions;282char *buf;283284file = NULL;285lastOptions = NULL;286offset = lastOffset = 0;287for (i = 0; i < elfInfo->stabCount; ++i) {288StabEntry *stab = ((StabEntry *)elfInfo->stabData->d_buf) + i;289290if (stab->n_type == 0 /* N_UNDEF */) {291offset = lastOffset;292lastOffset += stab-> n_value;293file = NULL; /* C++ output files seem not to have N_OBJ fields.*/294lastOptions = NULL;295sourceFile = getStabString(elfInfo, stab->n_strx + offset);296}297else if (stab->n_type == 0x24 /* N_FUN */) {298const char *stabName;299char *p1, *p2;300301stabName = getStabString(elfInfo, stab->n_strx + offset);302if (strcmp (stabName, name) == 0) {303304if (file != NULL)305return file;306307if (lastOptions == NULL)308return NULL;309310p1 = strstr(lastOptions, ";ptr");311if (p1 == NULL)312return NULL;313p1 += 4;314p2 = index(p1, ';');315if (p2 == NULL)316return NULL;317318buf = (char *)malloc(p2 - p1 + strlen(sourceFile) + 10);319strncpy(buf, p1, p2 - p1);320buf[p2-p1] = '/';321strcpy(buf + (p2 - p1) + 1, sourceFile);322p1 = rindex(buf, '.');323if (p1 == NULL)324return NULL;325p1[1] = 'o';326p1[2] = '\0';327return buf;328}329}330else if (stab->n_type == 0x3c /* N_OPT */) {331lastOptions = getStabString(elfInfo, stab->n_strx + offset);332}333else if (stab->n_type == 0x38 /* N_OBJ */) {334file = getStabString(elfInfo, stab->n_strx + offset);335}336}337return NULL;338}339340341static const char *checkObjFileList(ElfInfo *elfInfo, const char *file) {342ObjFileList *objFileList;343int len = strlen(file);344int nameLen;345const char *objFileName;346347/*fprintf(stderr, "checkObjFileList(%s).\n", file);*/348for (objFileList = elfInfo->objFileList; objFileList != NULL;349objFileList = objFileList->next) {350351objFileName = objFileList->objFileName;352nameLen = objFileList->nameLen;353if (strcmp(objFileName +nameLen - len, file) != 0)354continue;355356if (len == nameLen)357return file;358359if (len > nameLen)360continue;361362if (*(objFileName + nameLen - len - 1) == '/')363return objFileName;364}365return file;366}367368369static void identifySymbol(ElfInfo *elfInfo, ElfXX_Addr value, int count)370{371int i;372ElfXX_Sym *bestFunc = NULL;373ElfXX_Sym *bestFile = NULL;374ElfXX_Sym *lastFile = NULL;375char fileName[MAXPATHLEN];376char buf[4096];377const char *file;378SymChain *chain;379const char *format;380381for (i = 0; i < elfInfo->symCount; ++i) {382ElfXX_Sym *sym = ((ElfXX_Sym *)elfInfo->symData->d_buf) + i;383if (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC) {384385if (sym->st_shndx == SHN_UNDEF)386continue;387388if (sym->st_value > value)389continue;390391if (bestFunc != NULL) {392393if (sym->st_value < bestFunc->st_value)394continue;395396/*397* If we have two symbols of equal value, we have a problem -398* we must pick the "right" one, which is the one the compiler399* used to generate the section name with -xF.400*401* The compiler has the nasty habit of generating two402* mangled names for some C++ functions.403*404* Try - picking the shortest name.405*/406407if (sym->st_value == bestFunc->st_value) {408if (strlen(getSymString(elfInfo, bestFunc->st_name)) <409strlen(getSymString(elfInfo, sym->st_name)))410continue;411}412413}414bestFunc = sym;415bestFile = lastFile;416}417else if (ELFXX_ST_TYPE(sym->st_info) == STT_FILE) {418lastFile = sym;419}420}421422if (bestFunc == NULL)423fail("Unable to find symbol for address 0x%x.\n", value);424425for (chain = elfInfo->symChainHead; chain != NULL; chain = chain->next) {426if (chain->sym == bestFunc)427return;428}429chain = (SymChain *)malloc(sizeof (SymChain));430chain->sym = bestFunc;431chain->next = elfInfo->symChainHead;432elfInfo->symChainHead = chain;433434435if (ELFXX_ST_BIND(bestFunc->st_info) == STB_GLOBAL)436file = "";437else {438const char *name = getSymString(elfInfo, bestFunc->st_name);439file = identifyFile(elfInfo, name);440if (file == NULL) {441if (bestFile == NULL) {442file = "notFound";443fail("Failed to identify %s.\n", name);444} else {445char *suffix;446fileName[0] = ':';447fileName[1] = ' ';448file = getSymString(elfInfo, bestFile->st_name);449strncpy(fileName+2, file, MAXPATHLEN-3);450suffix = rindex(fileName, '.');451if (suffix == NULL)452fail("no file name suffix?");453suffix[1] = 'o';454suffix[2] = '\0';455456file = checkObjFileList(elfInfo, fileName+2);457if (file != fileName+2)458strncpy(fileName+2, file, MAXPATHLEN-3);459460file = fileName;461}462} else {463fileName[0] = ':';464fileName[1] = ' ';465strncpy(fileName + 2, file, MAXPATHLEN-3);466file = fileName;467}468}469format = "text: .text%%%s%s;\n";470i = snprintf(buf, sizeof buf, format,471bestFunc ? getSymString(elfInfo, bestFunc->st_name) : "notFound",472file);473write(2, buf, i);474}475476477static mutex_t mutex;478static int orderByCount = FALSE;479480481static void init_mcount(void)482{483mutex_init(&mutex, USYNC_THREAD, NULL);484}485486#pragma init(init_mcount)487488489typedef struct CountAddrPair {490int count;491unsigned int addr;492} CountAddrPair;493494495static int compareCounts(const void *a, const void *b) {496return ((CountAddrPair *)b)->count - ((CountAddrPair *)a)->count;497}498499static int compareCountsReverse(const void *a, const void *b) {500return ((CountAddrPair *)a)->count - ((CountAddrPair *)b)->count;501}502503504static void doCounts(void) {505unsigned int i;506int n;507int nMethods;508int nMethods2;509CountAddrPair *pairs;510ElfInfo *elfInfo;511512elfInfo = createElfInfo(libFileName);513514nMethods = 0;515for (i = 0; i < COUNT_BUF_SIZE >> 2; ++i) {516n = countBuf[i];517if (n > 0)518++nMethods;519}520pairs = (CountAddrPair *)malloc(sizeof(CountAddrPair) * nMethods);521nMethods2 = 0;522for (i = 0; i < COUNT_BUF_SIZE >> 2; ++i) {523n = countBuf[i];524if (n > 0) {525pairs[nMethods2].count = n;526pairs[nMethods2].addr = i << 2;527++nMethods2;528if (nMethods2 > nMethods) {529fprintf(stderr, "Number of methods detected increased after"530" the atexit call.\n");531break;532}533}534}535if (orderByCount) {536qsort(pairs, nMethods, sizeof pairs[0], &compareCounts);537for (i = 0; i < nMethods; ++i) {538identifySymbol(elfInfo, pairs[i].addr, pairs[i].count);539}540}541else {542qsort(pairs, nMethods, sizeof pairs[0], &compareCountsReverse);543for (i = 0; i < nMethods; ++i) {544identifySymbol(elfInfo, pairs[i].addr, 0);545}546}547}548549550static void __mcount(void *i0)551{552Dl_info info;553unsigned int offset;554int *p;555static int callsCounted = 0;556static int initialized = FALSE;557558if (!initialized) {559dladdr(i0, &info);560libFileName = info.dli_fname;561#if 0562fprintf(stderr, "Profiling %s\n", libFileName);563#endif564textOffset = info.dli_fbase;565if (getenv("MCOUNT_ORDER_BY_COUNT") != NULL) {566orderByCount = TRUE;567}568countBuf = (int *)malloc(COUNT_BUF_SIZE);569memset(countBuf, 0, COUNT_BUF_SIZE);570atexit(&doCounts);571initialized = TRUE;572}573574if ((uintptr_t)i0 < (uintptr_t)textOffset) {575fprintf(stderr, "mcount: function being profiled out of range????\n");576fprintf(stderr, " profiling more than one library at once????\n");577#if 0578dladdr(i0, &info);579fprintf(stderr, "Problem with %s in %s ???\n",580info.dli_sname, info.dli_fname);581#endif582fflush(stderr);583exit(666);584}585offset = ((uintptr_t)i0) - ((uintptr_t)textOffset);586if (offset > COUNT_BUF_SIZE) {587fprintf(stderr, "mcount: internal buffer too small for test.\n");588fprintf(stderr, " or function being profiled out of range????\n");589fprintf(stderr, " or profiling more than one library at once????\n");590#if 0591dladdr(i0, &info);592fprintf(stderr, "Problem with %s in %s ???\n",593info.dli_sname, info.dli_fname);594#endif595fflush(stderr);596exit(666);597}598599p = &countBuf[offset >>2];600if (orderByCount) {601++*p;602}603else {604if (*p == 0) {605*p = ++callsCounted;606}607}608}609610611void _mcount(void)612{613__mcount(_getReturnAddr());614}615616617void mcount(void)618{619__mcount(_getReturnAddr());620}621622623