1 /*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <stdio.h>
27 #include <sys/mman.h>
28 #include <dlfcn.h>
29 #include <libelf.h>
30 #include <strings.h>
31 #include <fcntl.h>
32 #include <sys/param.h>
33 #include <stdlib.h>
34 #include <thread.h>
35 #include <synch.h>
36 #include <stdarg.h>
37 #include <unistd.h>
38
39 #define TRUE 1
40 #define FALSE 0
41
42 /* 32/64 bit build issues. */
43
44 #ifdef _LP64
45 #define ElfXX_Sym Elf64_Sym
46 #define ElfXX_Ehdr Elf64_Ehdr
47 #define ElfXX_Shdr Elf64_Shdr
48 #define elfXX_getehdr elf64_getehdr
49 #define ElfXX_Addr Elf64_Addr
50 #define ELFXX_ST_TYPE ELF64_ST_TYPE
51 #define ELFXX_ST_BIND ELF64_ST_BIND
52 #define elfXX_getshdr elf64_getshdr
53 #else
54 #define ElfXX_Sym Elf32_Sym
55 #define ElfXX_Ehdr Elf32_Ehdr
56 #define ElfXX_Shdr Elf32_Shdr
57 #define elfXX_getehdr elf32_getehdr
58 #define ElfXX_Addr Elf32_Addr
59 #define ELFXX_ST_TYPE ELF32_ST_TYPE
60 #define ELFXX_ST_BIND ELF32_ST_BIND
61 #define elfXX_getshdr elf32_getshdr
62 #endif
63
64 extern void *_getReturnAddr(void);
65
66
67
68 typedef struct StabEntry {
69 unsigned n_strx;
70 unsigned char n_type;
71 char n_other;
72 short n_desc;
73 unsigned n_value;
74 } StabEntry;
75
76
77 typedef struct SymChain {
78 struct SymChain *next;
79 ElfXX_Sym *sym;
80 } SymChain;
81
82
83 typedef struct ObjFileList {
84 struct ObjFileList *next;
85 const char *objFileName;
86 int nameLen;
87 } ObjFileList;
88
89
90 typedef struct ElfInfo {
91 const char *fullName;
92 const char *baseName;
93 FILE *outFile;
94 int fd;
95 Elf *elf;
96 Elf_Data *sectionStringData;
97 Elf_Data *symData;
98 Elf_Data *symStringData;
99 int symCount;
100 SymChain *symChainHead;
101 Elf_Data *stabData;
102 Elf_Data *stabStringData;
103 int stabCount;
104 ObjFileList *objFileList;
105 } ElfInfo;
106
107
108
109 #define COUNT_BUF_SIZE (16*1024*1024)
110
111 #define ENTRY_CHAIN_BUCKETS 4999
112
113 static int *countBuf;
114 static void *textOffset;
115 static const char *libFileName;
116
117
118
fail(const char * err,...)119 static void fail(const char *err, ...)
120 {
121 va_list ap;
122 va_start(ap, err);
123 vfprintf(stderr, err, ap);
124 fflush(stderr);
125 va_end(ap);
126 }
127
128
129
getSymString(ElfInfo * elfInfo,int index)130 static const char *getSymString(ElfInfo *elfInfo, int index)
131 {
132 return (const char *)elfInfo->symStringData->d_buf + index;
133 }
134
135
getStabString(ElfInfo * elfInfo,int index)136 static const char *getStabString(ElfInfo *elfInfo, int index)
137 {
138 return (const char *)elfInfo->stabStringData->d_buf + index;
139 }
140
141
getSectionString(ElfInfo * elfInfo,int index)142 static const char *getSectionString(ElfInfo *elfInfo, int index)
143 {
144 return (const char *)elfInfo->sectionStringData->d_buf + index;
145 }
146
147
makeObjFileList(ElfInfo * elfInfo)148 static const char *makeObjFileList(ElfInfo *elfInfo)
149 {
150 int i;
151 const char *file;
152 unsigned offset, lastOffset;
153 ObjFileList *objFileList;
154
155 file = NULL;
156 offset = lastOffset = 0;
157 for (i = 0; i < elfInfo->stabCount; ++i) {
158 StabEntry *stab = ((StabEntry *)elfInfo->stabData->d_buf) + i;
159
160 if (stab->n_type == 0 /* N_UNDEF */) {
161 offset = lastOffset;
162 lastOffset += stab-> n_value;
163 }
164 else if (stab->n_type == 0x38 /* N_OBJ */) {
165 file = getStabString(elfInfo, stab->n_strx + offset);
166 objFileList = (ObjFileList *)malloc(sizeof (ObjFileList));
167 objFileList->objFileName = file;
168 /*fprintf(stderr,"new obj file %s.\n", file);*/
169 objFileList->nameLen = strlen(file);
170 objFileList->next = elfInfo->objFileList;
171 elfInfo->objFileList = objFileList;
172 }
173 }
174 return NULL;
175 }
176
177
createElfInfo(const char * fullName)178 static ElfInfo *createElfInfo(const char *fullName)
179 {
180 ElfInfo *elfInfo;
181 ElfXX_Ehdr *ehdr;
182 Elf_Scn *sectionStringSection;
183 Elf_Scn *stringSection;
184 Elf_Scn *symSection;
185 ElfXX_Shdr *symHeader;
186 Elf_Scn *stabSection;
187 ElfXX_Shdr *stabHeader;
188 ElfXX_Shdr *stringHeader;
189 Elf *elf;
190 const char *p;
191
192 /*fprintf(stderr, "# mapfile info for %s.\n", fullName);*/
193 elfInfo = (ElfInfo *)malloc(sizeof (ElfInfo));
194 memset(elfInfo, 0, sizeof (ElfInfo));
195 elfInfo->fullName = strdup(fullName);
196 p = rindex(elfInfo->fullName, '/');
197 elfInfo->baseName = (p == NULL) ? elfInfo->fullName : p + 1;
198
199 /* Open the ELF file. Get section headers. */
200
201 elf_version(EV_CURRENT);
202 elfInfo->fd = open(fullName, O_RDONLY);
203 if (elfInfo->fd < 0)
204 fail("Unable to open ELF file %s.\n", fullName);
205 elf = elf_begin(elfInfo->fd, ELF_C_READ, (Elf *)0);
206 if (elf == NULL)
207 fail("elf_begin failed.\n");
208 ehdr = elfXX_getehdr(elf);
209 sectionStringSection = elf_getscn(elf, ehdr->e_shstrndx);
210 elfInfo->sectionStringData = elf_getdata(sectionStringSection, NULL);
211
212 /* Find the symbol table section. */
213
214 symSection = NULL;
215 while ((symSection = elf_nextscn(elf, symSection)) != NULL) {
216 symHeader = elfXX_getshdr(symSection);
217 p = getSectionString(elfInfo, symHeader->sh_name);
218 if (strcmp(p, ".symtab") == 0)
219 break;
220 }
221 if (symSection == NULL)
222 fail("Unable to find symbol table.\n");
223
224 elfInfo->symData = elf_getdata(symSection, NULL);
225 elfInfo->symCount = elfInfo->symData->d_size / sizeof (ElfXX_Sym);
226
227 /* Find the string section. */
228
229 stringSection = NULL;
230 while ((stringSection = elf_nextscn(elf, stringSection)) != NULL) {
231 stringHeader = elfXX_getshdr(stringSection);
232 p = getSectionString(elfInfo, stringHeader->sh_name);
233 if (strcmp(p, ".strtab") == 0)
234 break;
235 }
236 if (stringSection == NULL)
237 fail("Unable to find string table.\n");
238
239 elfInfo->symStringData = elf_getdata(stringSection, NULL);
240 elfInfo->symChainHead = NULL;
241
242 /* Find the stab section. */
243
244 stabSection = NULL;
245 while ((stabSection = elf_nextscn(elf, stabSection)) != NULL) {
246 stabHeader = elfXX_getshdr(stabSection);
247 p = getSectionString(elfInfo, stabHeader->sh_name);
248 if (strcmp(p, ".stab.index") == 0)
249 break;
250 }
251 if (stabSection == NULL)
252 fail("Unable to find .stab.index.\n");
253
254 elfInfo->stabData = elf_getdata(stabSection, NULL);
255 elfInfo->stabCount = elfInfo->stabData->d_size / sizeof (StabEntry);
256
257 /* Find the string section. */
258
259 stringSection = NULL;
260 while ((stringSection = elf_nextscn(elf, stringSection)) != NULL) {
261 stringHeader = elfXX_getshdr(stringSection);
262 p = getSectionString(elfInfo, stringHeader->sh_name);
263 if (strcmp(p, ".stab.indexstr") == 0)
264 break;
265 }
266 if (stringSection == NULL)
267 fail("Unable to find .stab.indexstr table.\n");
268
269 elfInfo->stabStringData = elf_getdata(stringSection, NULL);
270 makeObjFileList(elfInfo);
271
272 return elfInfo;
273 }
274
275
identifyFile(ElfInfo * elfInfo,const char * name)276 static const char *identifyFile(ElfInfo *elfInfo, const char *name)
277 {
278 int i;
279 const char *file;
280 const char *sourceFile;
281 unsigned offset, lastOffset;
282 const char *lastOptions;
283 char *buf;
284
285 file = NULL;
286 lastOptions = NULL;
287 offset = lastOffset = 0;
288 for (i = 0; i < elfInfo->stabCount; ++i) {
289 StabEntry *stab = ((StabEntry *)elfInfo->stabData->d_buf) + i;
290
291 if (stab->n_type == 0 /* N_UNDEF */) {
292 offset = lastOffset;
293 lastOffset += stab-> n_value;
294 file = NULL; /* C++ output files seem not to have N_OBJ fields.*/
295 lastOptions = NULL;
296 sourceFile = getStabString(elfInfo, stab->n_strx + offset);
297 }
298 else if (stab->n_type == 0x24 /* N_FUN */) {
299 const char *stabName;
300 char *p1, *p2;
301
302 stabName = getStabString(elfInfo, stab->n_strx + offset);
303 if (strcmp (stabName, name) == 0) {
304
305 if (file != NULL)
306 return file;
307
308 if (lastOptions == NULL)
309 return NULL;
310
311 p1 = strstr(lastOptions, ";ptr");
312 if (p1 == NULL)
313 return NULL;
314 p1 += 4;
315 p2 = index(p1, ';');
316 if (p2 == NULL)
317 return NULL;
318
319 buf = (char *)malloc(p2 - p1 + strlen(sourceFile) + 10);
320 strncpy(buf, p1, p2 - p1);
321 buf[p2-p1] = '/';
322 strcpy(buf + (p2 - p1) + 1, sourceFile);
323 p1 = rindex(buf, '.');
324 if (p1 == NULL)
325 return NULL;
326 p1[1] = 'o';
327 p1[2] = '\0';
328 return buf;
329 }
330 }
331 else if (stab->n_type == 0x3c /* N_OPT */) {
332 lastOptions = getStabString(elfInfo, stab->n_strx + offset);
333 }
334 else if (stab->n_type == 0x38 /* N_OBJ */) {
335 file = getStabString(elfInfo, stab->n_strx + offset);
336 }
337 }
338 return NULL;
339 }
340
341
checkObjFileList(ElfInfo * elfInfo,const char * file)342 static const char *checkObjFileList(ElfInfo *elfInfo, const char *file) {
343 ObjFileList *objFileList;
344 int len = strlen(file);
345 int nameLen;
346 const char *objFileName;
347
348 /*fprintf(stderr, "checkObjFileList(%s).\n", file);*/
349 for (objFileList = elfInfo->objFileList; objFileList != NULL;
350 objFileList = objFileList->next) {
351
352 objFileName = objFileList->objFileName;
353 nameLen = objFileList->nameLen;
354 if (strcmp(objFileName +nameLen - len, file) != 0)
355 continue;
356
357 if (len == nameLen)
358 return file;
359
360 if (len > nameLen)
361 continue;
362
363 if (*(objFileName + nameLen - len - 1) == '/')
364 return objFileName;
365 }
366 return file;
367 }
368
369
identifySymbol(ElfInfo * elfInfo,ElfXX_Addr value,int count)370 static void identifySymbol(ElfInfo *elfInfo, ElfXX_Addr value, int count)
371 {
372 int i;
373 ElfXX_Sym *bestFunc = NULL;
374 ElfXX_Sym *bestFile = NULL;
375 ElfXX_Sym *lastFile = NULL;
376 char fileName[MAXPATHLEN];
377 char buf[4096];
378 const char *file;
379 SymChain *chain;
380 const char *format;
381
382 for (i = 0; i < elfInfo->symCount; ++i) {
383 ElfXX_Sym *sym = ((ElfXX_Sym *)elfInfo->symData->d_buf) + i;
384 if (ELFXX_ST_TYPE(sym->st_info) == STT_FUNC) {
385
386 if (sym->st_shndx == SHN_UNDEF)
387 continue;
388
389 if (sym->st_value > value)
390 continue;
391
392 if (bestFunc != NULL) {
393
394 if (sym->st_value < bestFunc->st_value)
395 continue;
396
397 /*
398 * If we have two symbols of equal value, we have a problem -
399 * we must pick the "right" one, which is the one the compiler
400 * used to generate the section name with -xF.
401 *
402 * The compiler has the nasty habit of generating two
403 * mangled names for some C++ functions.
404 *
405 * Try - picking the shortest name.
406 */
407
408 if (sym->st_value == bestFunc->st_value) {
409 if (strlen(getSymString(elfInfo, bestFunc->st_name)) <
410 strlen(getSymString(elfInfo, sym->st_name)))
411 continue;
412 }
413
414 }
415 bestFunc = sym;
416 bestFile = lastFile;
417 }
418 else if (ELFXX_ST_TYPE(sym->st_info) == STT_FILE) {
419 lastFile = sym;
420 }
421 }
422
423 if (bestFunc == NULL)
424 fail("Unable to find symbol for address 0x%x.\n", value);
425
426 for (chain = elfInfo->symChainHead; chain != NULL; chain = chain->next) {
427 if (chain->sym == bestFunc)
428 return;
429 }
430 chain = (SymChain *)malloc(sizeof (SymChain));
431 chain->sym = bestFunc;
432 chain->next = elfInfo->symChainHead;
433 elfInfo->symChainHead = chain;
434
435
436 if (ELFXX_ST_BIND(bestFunc->st_info) == STB_GLOBAL)
437 file = "";
438 else {
439 const char *name = getSymString(elfInfo, bestFunc->st_name);
440 file = identifyFile(elfInfo, name);
441 if (file == NULL) {
442 if (bestFile == NULL) {
443 file = "notFound";
444 fail("Failed to identify %s.\n", name);
445 } else {
446 char *suffix;
447 fileName[0] = ':';
448 fileName[1] = ' ';
449 file = getSymString(elfInfo, bestFile->st_name);
450 strncpy(fileName+2, file, MAXPATHLEN-3);
451 suffix = rindex(fileName, '.');
452 if (suffix == NULL)
453 fail("no file name suffix?");
454 suffix[1] = 'o';
455 suffix[2] = '\0';
456
457 file = checkObjFileList(elfInfo, fileName+2);
458 if (file != fileName+2)
459 strncpy(fileName+2, file, MAXPATHLEN-3);
460
461 file = fileName;
462 }
463 } else {
464 fileName[0] = ':';
465 fileName[1] = ' ';
466 strncpy(fileName + 2, file, MAXPATHLEN-3);
467 file = fileName;
468 }
469 }
470 format = "text: .text%%%s%s;\n";
471 i = snprintf(buf, sizeof buf, format,
472 bestFunc ? getSymString(elfInfo, bestFunc->st_name) : "notFound",
473 file);
474 write(2, buf, i);
475 }
476
477
478 static mutex_t mutex;
479 static int orderByCount = FALSE;
480
481
init_mcount(void)482 static void init_mcount(void)
483 {
484 mutex_init(&mutex, USYNC_THREAD, NULL);
485 }
486
487 #pragma init(init_mcount)
488
489
490 typedef struct CountAddrPair {
491 int count;
492 unsigned int addr;
493 } CountAddrPair;
494
495
compareCounts(const void * a,const void * b)496 static int compareCounts(const void *a, const void *b) {
497 return ((CountAddrPair *)b)->count - ((CountAddrPair *)a)->count;
498 }
499
compareCountsReverse(const void * a,const void * b)500 static int compareCountsReverse(const void *a, const void *b) {
501 return ((CountAddrPair *)a)->count - ((CountAddrPair *)b)->count;
502 }
503
504
doCounts(void)505 static void doCounts(void) {
506 unsigned int i;
507 int n;
508 int nMethods;
509 int nMethods2;
510 CountAddrPair *pairs;
511 ElfInfo *elfInfo;
512
513 elfInfo = createElfInfo(libFileName);
514
515 nMethods = 0;
516 for (i = 0; i < COUNT_BUF_SIZE >> 2; ++i) {
517 n = countBuf[i];
518 if (n > 0)
519 ++nMethods;
520 }
521 pairs = (CountAddrPair *)malloc(sizeof(CountAddrPair) * nMethods);
522 nMethods2 = 0;
523 for (i = 0; i < COUNT_BUF_SIZE >> 2; ++i) {
524 n = countBuf[i];
525 if (n > 0) {
526 pairs[nMethods2].count = n;
527 pairs[nMethods2].addr = i << 2;
528 ++nMethods2;
529 if (nMethods2 > nMethods) {
530 fprintf(stderr, "Number of methods detected increased after"
531 " the atexit call.\n");
532 break;
533 }
534 }
535 }
536 if (orderByCount) {
537 qsort(pairs, nMethods, sizeof pairs[0], &compareCounts);
538 for (i = 0; i < nMethods; ++i) {
539 identifySymbol(elfInfo, pairs[i].addr, pairs[i].count);
540 }
541 }
542 else {
543 qsort(pairs, nMethods, sizeof pairs[0], &compareCountsReverse);
544 for (i = 0; i < nMethods; ++i) {
545 identifySymbol(elfInfo, pairs[i].addr, 0);
546 }
547 }
548 }
549
550
__mcount(void * i0)551 static void __mcount(void *i0)
552 {
553 Dl_info info;
554 unsigned int offset;
555 int *p;
556 static int callsCounted = 0;
557 static int initialized = FALSE;
558
559 if (!initialized) {
560 dladdr(i0, &info);
561 libFileName = info.dli_fname;
562 #if 0
563 fprintf(stderr, "Profiling %s\n", libFileName);
564 #endif
565 textOffset = info.dli_fbase;
566 if (getenv("MCOUNT_ORDER_BY_COUNT") != NULL) {
567 orderByCount = TRUE;
568 }
569 countBuf = (int *)malloc(COUNT_BUF_SIZE);
570 memset(countBuf, 0, COUNT_BUF_SIZE);
571 atexit(&doCounts);
572 initialized = TRUE;
573 }
574
575 if ((uintptr_t)i0 < (uintptr_t)textOffset) {
576 fprintf(stderr, "mcount: function being profiled out of range????\n");
577 fprintf(stderr, " profiling more than one library at once????\n");
578 #if 0
579 dladdr(i0, &info);
580 fprintf(stderr, "Problem with %s in %s ???\n",
581 info.dli_sname, info.dli_fname);
582 #endif
583 fflush(stderr);
584 exit(666);
585 }
586 offset = ((uintptr_t)i0) - ((uintptr_t)textOffset);
587 if (offset > COUNT_BUF_SIZE) {
588 fprintf(stderr, "mcount: internal buffer too small for test.\n");
589 fprintf(stderr, " or function being profiled out of range????\n");
590 fprintf(stderr, " or profiling more than one library at once????\n");
591 #if 0
592 dladdr(i0, &info);
593 fprintf(stderr, "Problem with %s in %s ???\n",
594 info.dli_sname, info.dli_fname);
595 #endif
596 fflush(stderr);
597 exit(666);
598 }
599
600 p = &countBuf[offset >>2];
601 if (orderByCount) {
602 ++*p;
603 }
604 else {
605 if (*p == 0) {
606 *p = ++callsCounted;
607 }
608 }
609 }
610
611
_mcount(void)612 void _mcount(void)
613 {
614 __mcount(_getReturnAddr());
615 }
616
617
mcount(void)618 void mcount(void)
619 {
620 __mcount(_getReturnAddr());
621 }
622