jruby-async-profiler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +4 -0
  5. data/README.md +35 -0
  6. data/Rakefile +2 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/ext/Rakefile +6 -0
  10. data/ext/async-profiler/.gitattributes +1 -0
  11. data/ext/async-profiler/.gitignore +6 -0
  12. data/ext/async-profiler/.travis.yml +11 -0
  13. data/ext/async-profiler/CHANGELOG.md +107 -0
  14. data/ext/async-profiler/JavaHome.class +0 -0
  15. data/ext/async-profiler/LICENSE +201 -0
  16. data/ext/async-profiler/Makefile +66 -0
  17. data/ext/async-profiler/README.md +487 -0
  18. data/ext/async-profiler/demo/SwingSet2.svg +2247 -0
  19. data/ext/async-profiler/docs/cddl1.txt +358 -0
  20. data/ext/async-profiler/profiler.sh +240 -0
  21. data/ext/async-profiler/src/allocTracer.cpp +155 -0
  22. data/ext/async-profiler/src/allocTracer.h +74 -0
  23. data/ext/async-profiler/src/arch.h +69 -0
  24. data/ext/async-profiler/src/arguments.cpp +265 -0
  25. data/ext/async-profiler/src/arguments.h +152 -0
  26. data/ext/async-profiler/src/codeCache.cpp +128 -0
  27. data/ext/async-profiler/src/codeCache.h +99 -0
  28. data/ext/async-profiler/src/engine.cpp +50 -0
  29. data/ext/async-profiler/src/engine.h +38 -0
  30. data/ext/async-profiler/src/flameGraph.cpp +770 -0
  31. data/ext/async-profiler/src/flameGraph.h +118 -0
  32. data/ext/async-profiler/src/flightRecorder.cpp +727 -0
  33. data/ext/async-profiler/src/flightRecorder.h +39 -0
  34. data/ext/async-profiler/src/frameName.cpp +189 -0
  35. data/ext/async-profiler/src/frameName.h +56 -0
  36. data/ext/async-profiler/src/itimer.cpp +49 -0
  37. data/ext/async-profiler/src/itimer.h +43 -0
  38. data/ext/async-profiler/src/jattach/jattach.c +437 -0
  39. data/ext/async-profiler/src/java/one/profiler/AsyncProfiler.java +160 -0
  40. data/ext/async-profiler/src/java/one/profiler/AsyncProfilerMXBean.java +43 -0
  41. data/ext/async-profiler/src/java/one/profiler/Counter.java +25 -0
  42. data/ext/async-profiler/src/java/one/profiler/Events.java +28 -0
  43. data/ext/async-profiler/src/javaApi.cpp +124 -0
  44. data/ext/async-profiler/src/lockTracer.cpp +161 -0
  45. data/ext/async-profiler/src/lockTracer.h +55 -0
  46. data/ext/async-profiler/src/mutex.cpp +33 -0
  47. data/ext/async-profiler/src/mutex.h +49 -0
  48. data/ext/async-profiler/src/os.h +45 -0
  49. data/ext/async-profiler/src/os_linux.cpp +129 -0
  50. data/ext/async-profiler/src/os_macos.cpp +115 -0
  51. data/ext/async-profiler/src/perfEvents.h +60 -0
  52. data/ext/async-profiler/src/perfEvents_linux.cpp +550 -0
  53. data/ext/async-profiler/src/perfEvents_macos.cpp +64 -0
  54. data/ext/async-profiler/src/profiler.cpp +952 -0
  55. data/ext/async-profiler/src/profiler.h +238 -0
  56. data/ext/async-profiler/src/spinLock.h +66 -0
  57. data/ext/async-profiler/src/stackFrame.h +57 -0
  58. data/ext/async-profiler/src/stackFrame_aarch64.cpp +75 -0
  59. data/ext/async-profiler/src/stackFrame_arm.cpp +58 -0
  60. data/ext/async-profiler/src/stackFrame_i386.cpp +82 -0
  61. data/ext/async-profiler/src/stackFrame_x64.cpp +113 -0
  62. data/ext/async-profiler/src/symbols.h +37 -0
  63. data/ext/async-profiler/src/symbols_linux.cpp +354 -0
  64. data/ext/async-profiler/src/symbols_macos.cpp +156 -0
  65. data/ext/async-profiler/src/vmEntry.cpp +173 -0
  66. data/ext/async-profiler/src/vmEntry.h +105 -0
  67. data/ext/async-profiler/src/vmStructs.cpp +104 -0
  68. data/ext/async-profiler/src/vmStructs.h +112 -0
  69. data/ext/async-profiler/src/wallClock.cpp +96 -0
  70. data/ext/async-profiler/src/wallClock.h +56 -0
  71. data/ext/async-profiler/test/AllocatingTarget.java +26 -0
  72. data/ext/async-profiler/test/LoadLibraryTest.java +21 -0
  73. data/ext/async-profiler/test/Target.java +31 -0
  74. data/ext/async-profiler/test/ThreadsTarget.java +35 -0
  75. data/ext/async-profiler/test/alloc-smoke-test.sh +36 -0
  76. data/ext/async-profiler/test/load-library-test.sh +35 -0
  77. data/ext/async-profiler/test/smoke-test.sh +37 -0
  78. data/ext/async-profiler/test/thread-smoke-test.sh +32 -0
  79. data/jruby-async-profiler.gemspec +32 -0
  80. data/lib/jruby/async/profiler.rb +10 -0
  81. data/lib/jruby/async/profiler/version.rb +7 -0
  82. metadata +155 -0
@@ -0,0 +1,82 @@
1
+ /*
2
+ * Copyright 2017 Andrei Pangin
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #ifdef __i386__
18
+
19
+ #include "stackFrame.h"
20
+
21
+
22
+ uintptr_t& StackFrame::pc() {
23
+ return (uintptr_t&)_ucontext->uc_mcontext.gregs[REG_EIP];
24
+ }
25
+
26
+ uintptr_t& StackFrame::sp() {
27
+ return (uintptr_t&)_ucontext->uc_mcontext.gregs[REG_ESP];
28
+ }
29
+
30
+ uintptr_t& StackFrame::fp() {
31
+ return (uintptr_t&)_ucontext->uc_mcontext.gregs[REG_EBP];
32
+ }
33
+
34
+ uintptr_t StackFrame::arg0() {
35
+ return stackAt(1);
36
+ }
37
+
38
+ uintptr_t StackFrame::arg1() {
39
+ return stackAt(2);
40
+ }
41
+
42
+ uintptr_t StackFrame::arg2() {
43
+ return stackAt(3);
44
+ }
45
+
46
+ uintptr_t StackFrame::arg3() {
47
+ return stackAt(4);
48
+ }
49
+
50
+ void StackFrame::ret() {
51
+ pc() = stackAt(0);
52
+ sp() += 4;
53
+ }
54
+
55
+
56
+ static inline bool withinCurrentStack(uintptr_t value) {
57
+ // Check that value is not too far from stack pointer of current context
58
+ void* real_sp;
59
+ return value - (uintptr_t)&real_sp <= 0xffff;
60
+ }
61
+
62
+ bool StackFrame::pop(bool trust_frame_pointer) {
63
+ if (!withinCurrentStack(sp())) {
64
+ return false;
65
+ }
66
+
67
+ if (trust_frame_pointer && withinCurrentStack(fp())) {
68
+ sp() = fp() + 8;
69
+ fp() = stackAt(-2);
70
+ pc() = stackAt(-1);
71
+ } else if (fp() == sp() || withinCurrentStack(stackAt(0))) {
72
+ fp() = stackAt(0);
73
+ pc() = stackAt(1);
74
+ sp() += 8;
75
+ } else {
76
+ pc() = stackAt(0);
77
+ sp() += 4;
78
+ }
79
+ return true;
80
+ }
81
+
82
+ #endif // __i386__
@@ -0,0 +1,113 @@
1
+ /*
2
+ * Copyright 2017 Andrei Pangin
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #ifdef __x86_64__
18
+
19
+ #include "stackFrame.h"
20
+
21
+
22
+ #ifdef __APPLE__
23
+ # define REG(l, m) _ucontext->uc_mcontext->__ss.m
24
+ #else
25
+ # define REG(l, m) _ucontext->uc_mcontext.gregs[l]
26
+ #endif
27
+
28
+
29
+ uintptr_t& StackFrame::pc() {
30
+ return (uintptr_t&)REG(REG_RIP, __rip);
31
+ }
32
+
33
+ uintptr_t& StackFrame::sp() {
34
+ return (uintptr_t&)REG(REG_RSP, __rsp);
35
+ }
36
+
37
+ uintptr_t& StackFrame::fp() {
38
+ return (uintptr_t&)REG(REG_RBP, __rbp);
39
+ }
40
+
41
+ uintptr_t StackFrame::arg0() {
42
+ return (uintptr_t)REG(REG_RDI, __rdi);
43
+ }
44
+
45
+ uintptr_t StackFrame::arg1() {
46
+ return (uintptr_t)REG(REG_RSI, __rsi);
47
+ }
48
+
49
+ uintptr_t StackFrame::arg2() {
50
+ return (uintptr_t)REG(REG_RDX, __rdx);
51
+ }
52
+
53
+ uintptr_t StackFrame::arg3() {
54
+ return (uintptr_t)REG(REG_RCX, __rcx);
55
+ }
56
+
57
+ void StackFrame::ret() {
58
+ pc() = stackAt(0);
59
+ sp() += 8;
60
+ }
61
+
62
+
63
+ static inline bool withinCurrentStack(uintptr_t value) {
64
+ // Check that value is not too far from stack pointer of current context
65
+ void* real_sp;
66
+ return value - (uintptr_t)&real_sp <= 0xffff;
67
+ }
68
+
69
+ static inline bool isFramePrologueEpilogue(uintptr_t pc) {
70
+ if (pc & 0xfff) {
71
+ // Make sure we are not at the page boundary, so that reading [pc - 1] is safe
72
+ unsigned int opcode = *(unsigned int*)(pc - 1);
73
+ if (opcode == 0xec834855) {
74
+ // push rbp
75
+ // sub rsp, $const
76
+ return true;
77
+ } else if (opcode == 0xec8b4855) {
78
+ // push rbp
79
+ // mov rbp, rsp
80
+ return true;
81
+ }
82
+ }
83
+
84
+ if (*(unsigned char*)pc == 0x5d && *(unsigned short*)(pc + 1) == 0x0585) {
85
+ // pop rbp
86
+ // test [polling_page], eax
87
+ return true;
88
+ }
89
+
90
+ return false;
91
+ }
92
+
93
+ bool StackFrame::pop(bool trust_frame_pointer) {
94
+ if (!withinCurrentStack(sp())) {
95
+ return false;
96
+ }
97
+
98
+ if (trust_frame_pointer && withinCurrentStack(fp())) {
99
+ sp() = fp() + 16;
100
+ fp() = stackAt(-2);
101
+ pc() = stackAt(-1);
102
+ } else if (fp() == sp() || withinCurrentStack(stackAt(0)) || isFramePrologueEpilogue(pc())) {
103
+ fp() = stackAt(0);
104
+ pc() = stackAt(1);
105
+ sp() += 16;
106
+ } else {
107
+ pc() = stackAt(0);
108
+ sp() += 8;
109
+ }
110
+ return true;
111
+ }
112
+
113
+ #endif // __x86_64__
@@ -0,0 +1,37 @@
1
+ /*
2
+ * Copyright 2017 Andrei Pangin
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #ifndef _SYMBOLS_H
18
+ #define _SYMBOLS_H
19
+
20
+ #include <set>
21
+ #include "arch.h"
22
+ #include "codeCache.h"
23
+ #include "mutex.h"
24
+
25
+
26
+ class Symbols {
27
+ private:
28
+ static Mutex _parse_lock;
29
+ static std::set<const void*> _parsed_libraries;
30
+
31
+ static void parseKernelSymbols(NativeCodeCache* cc);
32
+
33
+ public:
34
+ static void parseLibraries(NativeCodeCache** array, volatile int& count, int size);
35
+ };
36
+
37
+ #endif // _SYMBOLS_H
@@ -0,0 +1,354 @@
1
+ /*
2
+ * Copyright 2017 Andrei Pangin
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #ifdef __linux__
18
+
19
+ #include <stdio.h>
20
+ #include <stdlib.h>
21
+ #include <string.h>
22
+ #include <sys/types.h>
23
+ #include <sys/stat.h>
24
+ #include <sys/mman.h>
25
+ #include <elf.h>
26
+ #include <errno.h>
27
+ #include <unistd.h>
28
+ #include <fcntl.h>
29
+ #include <linux/limits.h>
30
+ #include <fstream>
31
+ #include <iostream>
32
+ #include <string>
33
+ #include "symbols.h"
34
+
35
+
36
+ class SymbolDesc {
37
+ private:
38
+ const char* _addr;
39
+ const char* _type;
40
+
41
+ public:
42
+ SymbolDesc(const char* s) {
43
+ _addr = s;
44
+ _type = strchr(_addr, ' ') + 1;
45
+ }
46
+
47
+ const char* addr() { return (const char*)strtoul(_addr, NULL, 16); }
48
+ char type() { return _type[0]; }
49
+ const char* name() { return _type + 2; }
50
+ };
51
+
52
+ class MemoryMapDesc {
53
+ private:
54
+ const char* _addr;
55
+ const char* _end;
56
+ const char* _perm;
57
+ const char* _offs;
58
+ const char* _device;
59
+ const char* _inode;
60
+ const char* _file;
61
+
62
+ public:
63
+ MemoryMapDesc(const char* s) {
64
+ _addr = s;
65
+ _end = strchr(_addr, '-') + 1;
66
+ _perm = strchr(_end, ' ') + 1;
67
+ _offs = strchr(_perm, ' ') + 1;
68
+ _device = strchr(_offs, ' ') + 1;
69
+ _inode = strchr(_device, ' ') + 1;
70
+ _file = strchr(_inode, ' ');
71
+
72
+ if (_file != NULL) {
73
+ while (*_file == ' ') _file++;
74
+ }
75
+ }
76
+
77
+ const char* file() { return _file; }
78
+ bool isExecutable() { return _perm[0] == 'r' && _perm[2] == 'x'; }
79
+ const char* addr() { return (const char*)strtoul(_addr, NULL, 16); }
80
+ const char* end() { return (const char*)strtoul(_end, NULL, 16); }
81
+ unsigned long offs() { return strtoul(_offs, NULL, 16); }
82
+ unsigned long inode() { return strtoul(_inode, NULL, 10); }
83
+ };
84
+
85
+
86
+ #ifdef __LP64__
87
+ const unsigned char ELFCLASS_SUPPORTED = ELFCLASS64;
88
+ typedef Elf64_Ehdr ElfHeader;
89
+ typedef Elf64_Shdr ElfSection;
90
+ typedef Elf64_Nhdr ElfNote;
91
+ typedef Elf64_Sym ElfSymbol;
92
+ #else
93
+ const unsigned char ELFCLASS_SUPPORTED = ELFCLASS32;
94
+ typedef Elf32_Ehdr ElfHeader;
95
+ typedef Elf32_Shdr ElfSection;
96
+ typedef Elf32_Nhdr ElfNote;
97
+ typedef Elf32_Sym ElfSymbol;
98
+ #endif // __LP64__
99
+
100
+
101
+ class ElfParser {
102
+ private:
103
+ NativeCodeCache* _cc;
104
+ const char* _base;
105
+ const char* _file_name;
106
+ ElfHeader* _header;
107
+ const char* _sections;
108
+
109
+ ElfParser(NativeCodeCache* cc, const char* base, const void* addr, const char* file_name = NULL) {
110
+ _cc = cc;
111
+ _base = base;
112
+ _file_name = file_name;
113
+ _header = (ElfHeader*)addr;
114
+ _sections = (const char*)addr + _header->e_shoff;
115
+ }
116
+
117
+ bool valid_header() {
118
+ unsigned char* ident = _header->e_ident;
119
+ return ident[0] == 0x7f && ident[1] == 'E' && ident[2] == 'L' && ident[3] == 'F'
120
+ && ident[4] == ELFCLASS_SUPPORTED && ident[5] == ELFDATA2LSB && ident[6] == EV_CURRENT
121
+ && _header->e_shstrndx != SHN_UNDEF;
122
+ }
123
+
124
+ ElfSection* section(int index) {
125
+ return (ElfSection*)(_sections + index * _header->e_shentsize);
126
+ }
127
+
128
+ const char* at(ElfSection* section) {
129
+ return (const char*)_header + section->sh_offset;
130
+ }
131
+
132
+ ElfSection* findSection(uint32_t type, const char* name);
133
+
134
+ void loadSymbols(bool use_debug);
135
+ bool loadSymbolsUsingBuildId();
136
+ bool loadSymbolsUsingDebugLink();
137
+ void loadSymbolTable(ElfSection* symtab);
138
+
139
+ public:
140
+ static bool parseFile(NativeCodeCache* cc, const char* base, const char* file_name, bool use_debug);
141
+ static void parseMem(NativeCodeCache* cc, const char* base);
142
+ };
143
+
144
+
145
+ ElfSection* ElfParser::findSection(uint32_t type, const char* name) {
146
+ const char* strtab = at(section(_header->e_shstrndx));
147
+
148
+ for (int i = 0; i < _header->e_shnum; i++) {
149
+ ElfSection* section = this->section(i);
150
+ if (section->sh_type == type && section->sh_name != 0) {
151
+ if (strcmp(strtab + section->sh_name, name) == 0) {
152
+ return section;
153
+ }
154
+ }
155
+ }
156
+
157
+ return NULL;
158
+ }
159
+
160
+ bool ElfParser::parseFile(NativeCodeCache* cc, const char* base, const char* file_name, bool use_debug) {
161
+ int fd = open(file_name, O_RDONLY);
162
+ if (fd == -1) {
163
+ return false;
164
+ }
165
+
166
+ size_t length = (size_t)lseek64(fd, 0, SEEK_END);
167
+ void* addr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
168
+ close(fd);
169
+
170
+ if (addr == MAP_FAILED) {
171
+ if (strcmp(file_name, "/") == 0) {
172
+ // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1843018
173
+ fprintf(stderr, "Could not parse symbols due to the OS bug\n");
174
+ } else {
175
+ fprintf(stderr, "Could not parse symbols from %s: %s\n", file_name, strerror(errno));
176
+ }
177
+ } else {
178
+ ElfParser elf(cc, base, addr, file_name);
179
+ elf.loadSymbols(use_debug);
180
+ munmap(addr, length);
181
+ }
182
+ return true;
183
+ }
184
+
185
+ void ElfParser::parseMem(NativeCodeCache* cc, const char* base) {
186
+ ElfParser elf(cc, base, base);
187
+ elf.loadSymbols(false);
188
+ }
189
+
190
+ void ElfParser::loadSymbols(bool use_debug) {
191
+ if (!valid_header()) {
192
+ return;
193
+ }
194
+
195
+ // Look for debug symbols in the original .so
196
+ ElfSection* section = findSection(SHT_SYMTAB, ".symtab");
197
+ if (section != NULL) {
198
+ loadSymbolTable(section);
199
+ return;
200
+ }
201
+
202
+ // Try to load symbols from an external debuginfo library
203
+ if (use_debug) {
204
+ if (loadSymbolsUsingBuildId() || loadSymbolsUsingDebugLink()) {
205
+ return;
206
+ }
207
+ }
208
+
209
+ // If everything else fails, load only exported symbols
210
+ section = findSection(SHT_DYNSYM, ".dynsym");
211
+ if (section != NULL) {
212
+ loadSymbolTable(section);
213
+ }
214
+ }
215
+
216
+ // Load symbols from /usr/lib/debug/.build-id/ab/cdef1234.debug, where abcdef1234 is Build ID
217
+ bool ElfParser::loadSymbolsUsingBuildId() {
218
+ ElfSection* section = findSection(SHT_NOTE, ".note.gnu.build-id");
219
+ if (section == NULL || section->sh_size <= 16) {
220
+ return false;
221
+ }
222
+
223
+ ElfNote* note = (ElfNote*)at(section);
224
+ if (note->n_namesz != 4 || note->n_descsz < 2 || note->n_descsz > 64) {
225
+ return false;
226
+ }
227
+
228
+ const char* build_id = (const char*)note + sizeof(*note) + 4;
229
+ int build_id_len = note->n_descsz;
230
+
231
+ char path[PATH_MAX];
232
+ char* p = path + sprintf(path, "/usr/lib/debug/.build-id/%02hhx/", build_id[0]);
233
+ for (int i = 1; i < build_id_len; i++) {
234
+ p += sprintf(p, "%02hhx", build_id[i]);
235
+ }
236
+ strcpy(p, ".debug");
237
+
238
+ return parseFile(_cc, _base, path, false);
239
+ }
240
+
241
+ // Look for debuginfo file specified in .gnu_debuglink section
242
+ bool ElfParser::loadSymbolsUsingDebugLink() {
243
+ ElfSection* section = findSection(SHT_PROGBITS, ".gnu_debuglink");
244
+ if (section == NULL || section->sh_size <= 4) {
245
+ return false;
246
+ }
247
+
248
+ const char* basename = strrchr(_file_name, '/');
249
+ if (basename == NULL) {
250
+ return false;
251
+ }
252
+
253
+ char* dirname = strndup(_file_name, basename - _file_name);
254
+ if (dirname == NULL) {
255
+ return false;
256
+ }
257
+
258
+ const char* debuglink = at(section);
259
+ char path[PATH_MAX];
260
+ bool result = false;
261
+
262
+ // 1. /path/to/libjvm.so.debug
263
+ if (strcmp(debuglink, basename + 1) != 0 &&
264
+ snprintf(path, PATH_MAX, "%s/%s", dirname, debuglink) < PATH_MAX) {
265
+ result = parseFile(_cc, _base, path, false);
266
+ }
267
+
268
+ // 2. /path/to/.debug/libjvm.so.debug
269
+ if (!result && snprintf(path, PATH_MAX, "%s/.debug/%s", dirname, debuglink) < PATH_MAX) {
270
+ result = parseFile(_cc, _base, path, false);
271
+ }
272
+
273
+ // 3. /usr/lib/debug/path/to/libjvm.so.debug
274
+ if (!result && snprintf(path, PATH_MAX, "/usr/lib/debug%s/%s", dirname, debuglink) < PATH_MAX) {
275
+ result = parseFile(_cc, _base, path, false);
276
+ }
277
+
278
+ free(dirname);
279
+ return result;
280
+ }
281
+
282
+ void ElfParser::loadSymbolTable(ElfSection* symtab) {
283
+ ElfSection* strtab = section(symtab->sh_link);
284
+ const char* strings = at(strtab);
285
+
286
+ const char* symbols = at(symtab);
287
+ const char* symbols_end = symbols + symtab->sh_size;
288
+ for (; symbols < symbols_end; symbols += symtab->sh_entsize) {
289
+ ElfSymbol* sym = (ElfSymbol*)symbols;
290
+ if (sym->st_name != 0 && sym->st_value != 0) {
291
+ _cc->add(_base + sym->st_value, (int)sym->st_size, strings + sym->st_name);
292
+ }
293
+ }
294
+ }
295
+
296
+
297
+ Mutex Symbols::_parse_lock;
298
+ std::set<const void*> Symbols::_parsed_libraries;
299
+
300
+ void Symbols::parseKernelSymbols(NativeCodeCache* cc) {
301
+ std::ifstream maps("/proc/kallsyms");
302
+ std::string str;
303
+
304
+ while (std::getline(maps, str)) {
305
+ str += "_[k]";
306
+ SymbolDesc symbol(str.c_str());
307
+ char type = symbol.type();
308
+ if (type == 'T' || type == 't' || type == 'W' || type == 'w') {
309
+ const char* addr = symbol.addr();
310
+ if (addr != NULL) {
311
+ cc->add(addr, 0, symbol.name());
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ void Symbols::parseLibraries(NativeCodeCache** array, volatile int& count, int size) {
318
+ MutexLocker ml(_parse_lock);
319
+
320
+ if (count == 0) {
321
+ NativeCodeCache* cc = new NativeCodeCache("[kernel]");
322
+ parseKernelSymbols(cc);
323
+ cc->sort();
324
+ array[count] = cc;
325
+ atomicInc(count);
326
+ }
327
+
328
+ std::ifstream maps("/proc/self/maps");
329
+ std::string str;
330
+
331
+ while (count < size && std::getline(maps, str)) {
332
+ MemoryMapDesc map(str.c_str());
333
+ if (map.isExecutable() && map.file() != NULL && map.file()[0] != 0) {
334
+ const char* image_base = map.addr();
335
+ if (!_parsed_libraries.insert(image_base).second) {
336
+ continue; // the library was already parsed
337
+ }
338
+
339
+ NativeCodeCache* cc = new NativeCodeCache(map.file(), image_base, map.end());
340
+
341
+ if (map.inode() != 0) {
342
+ ElfParser::parseFile(cc, image_base - map.offs(), map.file(), true);
343
+ } else if (strcmp(map.file(), "[vdso]") == 0) {
344
+ ElfParser::parseMem(cc, image_base);
345
+ }
346
+
347
+ cc->sort();
348
+ array[count] = cc;
349
+ atomicInc(count);
350
+ }
351
+ }
352
+ }
353
+
354
+ #endif // __linux__