author | brutisso |
Tue, 20 Oct 2015 14:00:00 +0200 | |
changeset 33229 | 51173444fdd5 |
parent 23010 | 6dadb192ad81 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
21805
diff
changeset
|
2 |
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 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 |
||
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 |
||
130 |
static const char *getSymString(ElfInfo *elfInfo, int index) |
|
131 |
{ |
|
132 |
return (const char *)elfInfo->symStringData->d_buf + index; |
|
133 |
} |
|
134 |
||
135 |
||
136 |
static const char *getStabString(ElfInfo *elfInfo, int index) |
|
137 |
{ |
|
138 |
return (const char *)elfInfo->stabStringData->d_buf + index; |
|
139 |
} |
|
140 |
||
141 |
||
142 |
static const char *getSectionString(ElfInfo *elfInfo, int index) |
|
143 |
{ |
|
144 |
return (const char *)elfInfo->sectionStringData->d_buf + index; |
|
145 |
} |
|
146 |
||
147 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
496 |
static int compareCounts(const void *a, const void *b) { |
|
497 |
return ((CountAddrPair *)b)->count - ((CountAddrPair *)a)->count; |
|
498 |
} |
|
499 |
||
500 |
static int compareCountsReverse(const void *a, const void *b) { |
|
501 |
return ((CountAddrPair *)a)->count - ((CountAddrPair *)b)->count; |
|
502 |
} |
|
503 |
||
504 |
||
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 |
||
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 |
||
612 |
void _mcount(void) |
|
613 |
{ |
|
614 |
__mcount(_getReturnAddr()); |
|
615 |
} |
|
616 |
||
617 |
||
618 |
void mcount(void) |
|
619 |
{ |
|
620 |
__mcount(_getReturnAddr()); |
|
621 |
} |