jruby-async-profiler 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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__