Mercurial > hg > truffle
annotate src/os/solaris/dtrace/libjvm_db.c @ 5693:0356d95f01ba
While inlining, ensure proper anchoring of things that where anchored to the StartNode
Fix killCFG case where some dead nodes would not be removed, leading to later NullPointerExceptions
Fix Switch nodes simplification in case the node of the remaining successor changes because of deleting the other branches
Fix addDuplicates : do not patch inputs to the outer world if these inputs would point to an other graph
author | Gilles Duboscq <duboscq@ssw.jku.at> |
---|---|
date | Tue, 26 Jun 2012 16:43:51 +0200 |
parents | 1d1603768966 |
children | 2fe087c3e814 |
rev | line source |
---|---|
0 | 1 /* |
2426
1d1603768966
7010070: Update all 2010 Oracle-changed OpenJDK files to have the proper copyright dates - second pass
trims
parents:
2344
diff
changeset
|
2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
0 | 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. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1123
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1123
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1123
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 #include <stdio.h> | |
26 #include <stdlib.h> | |
27 #include <string.h> | |
28 #include <errno.h> | |
29 #include <gelf.h> | |
30 | |
31 #include "libjvm_db.h" | |
32 #include "JvmOffsets.h" | |
33 | |
34 #define LIBJVM_SO "libjvm.so" | |
35 | |
36 #if defined(i386) || defined(__i386) || defined(__amd64) | |
37 #ifdef COMPILER2 | |
38 #define X86_COMPILER2 | |
39 #endif /* COMPILER2 */ | |
40 #endif /* i386 */ | |
41 | |
42 typedef struct { | |
43 short vf_cnt; /* number of recognized java vframes */ | |
44 short bci; /* current frame method byte code index */ | |
45 int line; /* current frame method source line */ | |
46 uint64_t new_fp; /* fp for the next frame */ | |
47 uint64_t new_pc; /* pc for the next frame */ | |
48 uint64_t new_sp; /* "raw" sp for the next frame (includes extension by interpreter/adapter */ | |
49 char locinf; /* indicates there is valid location info */ | |
50 } Jframe_t; | |
51 | |
52 int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name, | |
53 size_t size, Jframe_t *jframe); | |
54 | |
55 int main(int arg) { return arg; } | |
56 | |
57 static int debug = 0; | |
58 | |
59 static void failed(int err, const char * file, int line) { | |
60 if (debug) { | |
61 fprintf(stderr, "failed %d at %s:%d\n", err, file, line); | |
62 } | |
63 } | |
64 | |
65 static void warn(const char * file, int line, const char * msg) { | |
66 if (debug) { | |
67 fprintf(stderr, "warning: %s at %s:%d\n", msg, file, line); | |
68 } | |
69 } | |
70 | |
71 static void warn1(const char * file, int line, const char * msg, intptr_t arg1) { | |
72 if (debug) { | |
73 fprintf(stderr, "warning: "); | |
74 fprintf(stderr, msg, arg1); | |
75 fprintf(stderr, " at %s:%d\n", file, line); | |
76 } | |
77 } | |
78 | |
79 #define CHECK_FAIL(err) \ | |
80 if (err != PS_OK) { failed(err, __FILE__, __LINE__); goto fail; } | |
81 #define WARN(msg) warn(__FILE__, __LINE__, msg) | |
82 #define WARN1(msg, arg1) warn1(__FILE__, __LINE__, msg, arg1) | |
83 | |
84 typedef struct VMStructEntry { | |
85 const char * typeName; /* The type name containing the given field (example: "Klass") */ | |
86 const char * fieldName; /* The field name within the type (example: "_name") */ | |
87 uint64_t address; /* Address of field; only used for static fields */ | |
88 /* ("offset" can not be reused because of apparent SparcWorks compiler bug */ | |
89 /* in generation of initializer data) */ | |
90 } VMStructEntry; | |
91 | |
92 /* Prototyping inlined methods */ | |
93 | |
94 int sprintf(char *s, const char *format, ...); | |
95 | |
96 #define SZ16 sizeof(int16_t) | |
97 #define SZ32 sizeof(int32_t) | |
98 | |
99 #define COMP_METHOD_SIGN '*' | |
100 | |
101 #define MAX_VFRAMES_CNT 256 | |
102 | |
103 typedef struct vframe { | |
104 uint64_t methodOop; | |
105 int32_t sender_decode_offset; | |
106 int32_t methodIdx; | |
107 int32_t bci; | |
108 int32_t line; | |
109 } Vframe_t; | |
110 | |
111 typedef struct frame { | |
112 uintptr_t fp; | |
113 uintptr_t pc; | |
114 uintptr_t sp; | |
115 uintptr_t sender_sp; // The unextended sp of the caller | |
116 } Frame_t; | |
117 | |
118 typedef struct Nmethod_t { | |
119 struct jvm_agent* J; | |
120 Jframe_t *jframe; | |
121 | |
122 uint64_t nm; /* _nmethod */ | |
123 uint64_t pc; | |
124 uint64_t pc_desc; | |
125 | |
126 int32_t orig_pc_offset; /* _orig_pc_offset */ | |
1748 | 127 int32_t instrs_beg; /* _code_offset */ |
0 | 128 int32_t instrs_end; |
129 int32_t deopt_beg; /* _deoptimize_offset */ | |
130 int32_t scopes_data_beg; /* _scopes_data_offset */ | |
131 int32_t scopes_data_end; | |
132 int32_t oops_beg; /* _oops_offset */ | |
1563
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
133 int32_t oops_end; |
0 | 134 int32_t scopes_pcs_beg; /* _scopes_pcs_offset */ |
135 int32_t scopes_pcs_end; | |
136 | |
137 int vf_cnt; | |
138 Vframe_t vframes[MAX_VFRAMES_CNT]; | |
139 } Nmethod_t; | |
140 | |
141 struct jvm_agent { | |
142 struct ps_prochandle* P; | |
143 | |
144 uint64_t nmethod_vtbl; | |
145 uint64_t CodeBlob_vtbl; | |
146 uint64_t BufferBlob_vtbl; | |
147 uint64_t RuntimeStub_vtbl; | |
148 | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
149 uint64_t Use_Compressed_Oops_address; |
0 | 150 uint64_t Universe_methodKlassObj_address; |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
151 uint64_t Universe_narrow_oop_base_address; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
152 uint64_t Universe_narrow_oop_shift_address; |
0 | 153 uint64_t CodeCache_heap_address; |
154 | |
155 /* Volatiles */ | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
156 uint8_t Use_Compressed_Oops; |
0 | 157 uint64_t Universe_methodKlassObj; |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
158 uint64_t Universe_narrow_oop_base; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
159 uint32_t Universe_narrow_oop_shift; |
0 | 160 uint64_t CodeCache_low; |
161 uint64_t CodeCache_high; | |
162 uint64_t CodeCache_segmap_low; | |
163 uint64_t CodeCache_segmap_high; | |
164 | |
165 int32_t SIZE_CodeCache_log2_segment; | |
166 | |
167 uint64_t methodOopPtr; | |
168 uint64_t bcx; | |
169 | |
170 Nmethod_t *N; /*Inlined methods support */ | |
171 Frame_t prev_fr; | |
172 Frame_t curr_fr; | |
173 }; | |
174 | |
175 static int | |
176 read_string(struct ps_prochandle *P, | |
177 char *buf, /* caller's buffer */ | |
178 size_t size, /* upper limit on bytes to read */ | |
179 uintptr_t addr) /* address in process */ | |
180 { | |
181 int err = PS_OK; | |
182 while (size-- > 1 && err == PS_OK) { | |
183 err = ps_pread(P, addr, buf, 1); | |
184 if (*buf == '\0') { | |
185 return PS_OK; | |
186 } | |
187 addr += 1; | |
188 buf += 1; | |
189 } | |
190 return -1; | |
191 } | |
192 | |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
193 static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
194 int err = -1; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
195 uint32_t ptr32; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
196 err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
197 *ptr = ptr32; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
198 return err; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
199 } |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
200 |
0 | 201 static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) { |
202 int err = -1; | |
203 uint32_t ptr32; | |
204 | |
205 switch (DATA_MODEL) { | |
206 case PR_MODEL_LP64: | |
207 err = ps_pread(J->P, base, ptr, sizeof(uint64_t)); | |
208 break; | |
209 case PR_MODEL_ILP32: | |
210 err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); | |
211 *ptr = ptr32; | |
212 break; | |
213 } | |
214 | |
215 return err; | |
216 } | |
217 | |
218 static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) { | |
219 uint64_t ptr; | |
220 int err; | |
221 char buffer[1024]; | |
222 | |
223 *stringp = NULL; | |
224 err = read_pointer(J, base, &ptr); | |
225 CHECK_FAIL(err); | |
226 if (ptr != 0) { | |
227 err = read_string(J->P, buffer, sizeof(buffer), ptr); | |
228 CHECK_FAIL(err); | |
229 *stringp = strdup(buffer); | |
230 } | |
231 return PS_OK; | |
232 | |
233 fail: | |
234 return err; | |
235 } | |
236 | |
237 static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) { | |
238 uint64_t ptr; | |
239 int err; | |
240 | |
241 err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName); | |
242 CHECK_FAIL(err); | |
243 err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName); | |
244 CHECK_FAIL(err); | |
245 err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address); | |
246 CHECK_FAIL(err); | |
247 | |
248 return PS_OK; | |
249 | |
250 fail: | |
251 if (vmp->typeName != NULL) free((void*)vmp->typeName); | |
252 if (vmp->fieldName != NULL) free((void*)vmp->fieldName); | |
253 return err; | |
254 } | |
255 | |
256 static int parse_vmstructs(jvm_agent_t* J) { | |
257 VMStructEntry vmVar; | |
258 VMStructEntry* vmp = &vmVar; | |
259 uint64_t gHotSpotVMStructs; | |
260 psaddr_t sym_addr; | |
261 uint64_t base; | |
262 int err; | |
263 | |
264 err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); | |
265 CHECK_FAIL(err); | |
266 err = read_pointer(J, sym_addr, &gHotSpotVMStructs); | |
267 CHECK_FAIL(err); | |
268 base = gHotSpotVMStructs; | |
269 | |
270 err = PS_OK; | |
271 while (err == PS_OK) { | |
272 memset(vmp, 0, sizeof(VMStructEntry)); | |
273 err = parse_vmstruct_entry(J, base, vmp); | |
274 if (err != PS_OK || vmp->typeName == NULL) { | |
275 break; | |
276 } | |
277 | |
278 if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { | |
279 if (strcmp("_heap", vmp->fieldName) == 0) { | |
280 err = read_pointer(J, vmp->address, &J->CodeCache_heap_address); | |
281 } | |
282 } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { | |
283 if (strcmp("_methodKlassObj", vmp->fieldName) == 0) { | |
284 J->Universe_methodKlassObj_address = vmp->address; | |
285 } | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
286 if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
287 J->Universe_narrow_oop_base_address = vmp->address; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
288 } |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
289 if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
290 J->Universe_narrow_oop_shift_address = vmp->address; |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
291 } |
0 | 292 } |
293 CHECK_FAIL(err); | |
294 | |
295 base += SIZE_VMStructEntry; | |
296 if (vmp->typeName != NULL) free((void*)vmp->typeName); | |
297 if (vmp->fieldName != NULL) free((void*)vmp->fieldName); | |
298 } | |
299 | |
300 return PS_OK; | |
301 | |
302 fail: | |
303 if (vmp->typeName != NULL) free((void*)vmp->typeName); | |
304 if (vmp->fieldName != NULL) free((void*)vmp->fieldName); | |
305 return -1; | |
306 } | |
307 | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
308 static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
309 psaddr_t sym_addr; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
310 int err; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
311 |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
312 err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
313 if (err != PS_OK) goto fail; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
314 *valuep = sym_addr; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
315 return PS_OK; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
316 |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
317 fail: |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
318 return err; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
319 } |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
320 |
0 | 321 static int read_volatiles(jvm_agent_t* J) { |
322 uint64_t ptr; | |
323 int err; | |
324 | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
325 err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
326 if (err == PS_OK) { |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
327 err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
328 CHECK_FAIL(err); |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
329 } else { |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
330 J->Use_Compressed_Oops = 0; |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
331 } |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
332 |
0 | 333 err = read_pointer(J, J->Universe_methodKlassObj_address, &J->Universe_methodKlassObj); |
334 CHECK_FAIL(err); | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
335 |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
336 err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
337 CHECK_FAIL(err); |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
338 err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
339 CHECK_FAIL(err); |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
340 |
0 | 341 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + |
342 OFFSET_VirtualSpace_low, &J->CodeCache_low); | |
343 CHECK_FAIL(err); | |
344 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + | |
345 OFFSET_VirtualSpace_high, &J->CodeCache_high); | |
346 CHECK_FAIL(err); | |
347 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + | |
348 OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low); | |
349 CHECK_FAIL(err); | |
350 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + | |
351 OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high); | |
352 CHECK_FAIL(err); | |
353 | |
354 err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size, | |
355 &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); | |
356 CHECK_FAIL(err); | |
357 | |
358 return PS_OK; | |
359 | |
360 fail: | |
361 return err; | |
362 } | |
363 | |
364 | |
365 static int codecache_contains(jvm_agent_t* J, uint64_t ptr) { | |
366 /* make sure the code cache is up to date */ | |
367 return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high); | |
368 } | |
369 | |
370 static uint64_t segment_for(jvm_agent_t* J, uint64_t p) { | |
371 return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment; | |
372 } | |
373 | |
374 static uint64_t block_at(jvm_agent_t* J, int i) { | |
375 return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment); | |
376 } | |
377 | |
378 static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { | |
379 int err; | |
380 | |
381 *startp = 0; | |
382 if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) { | |
383 int32_t used; | |
384 uint64_t segment = segment_for(J, ptr); | |
385 uint64_t block = J->CodeCache_segmap_low; | |
386 uint8_t tag; | |
387 err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); | |
388 CHECK_FAIL(err); | |
389 if (tag == 0xff) | |
390 return PS_OK; | |
391 while (tag > 0) { | |
392 err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); | |
393 CHECK_FAIL(err); | |
394 segment -= tag; | |
395 } | |
396 block = block_at(J, segment); | |
397 err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); | |
398 CHECK_FAIL(err); | |
399 if (used) { | |
400 *startp = block + SIZE_HeapBlockHeader; | |
401 } | |
402 } | |
403 return PS_OK; | |
404 | |
405 fail: | |
406 return -1; | |
407 } | |
408 | |
409 static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { | |
410 psaddr_t sym_addr; | |
411 int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); | |
412 if (err == PS_OK) { | |
413 err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); | |
414 return err; | |
415 } | |
416 *valuep = -1; | |
417 return -1; | |
418 } | |
419 | |
420 jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) { | |
421 jvm_agent_t* J; | |
422 int err; | |
423 | |
424 if (vers != JVM_DB_VERSION) { | |
425 errno = ENOTSUP; | |
426 return NULL; | |
427 } | |
428 | |
429 J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1); | |
430 | |
431 debug = getenv("LIBJVMDB_DEBUG") != NULL; | |
432 if (debug) debug = 3; | |
433 | |
434 if (debug) { | |
435 fprintf(stderr, "Jagent_create: debug=%d\n", debug); | |
436 #ifdef X86_COMPILER2 | |
437 fprintf(stderr, "Jagent_create: R_SP=%d, R_FP=%d, POINTER_SIZE=%d\n", R_SP, R_FP, POINTER_SIZE); | |
438 #endif /* X86_COMPILER2 */ | |
439 } | |
440 | |
441 J->P = P; | |
442 | |
443 // Initialize the initial previous frame | |
444 | |
445 J->prev_fr.fp = 0; | |
446 J->prev_fr.pc = 0; | |
447 J->prev_fr.sp = 0; | |
448 J->prev_fr.sender_sp = 0; | |
449 | |
450 err = find_symbol(J, "__1cHnmethodG__vtbl_", &J->nmethod_vtbl); | |
451 CHECK_FAIL(err); | |
452 err = find_symbol(J, "__1cKBufferBlobG__vtbl_", &J->BufferBlob_vtbl); | |
453 if (err != PS_OK) J->BufferBlob_vtbl = 0; | |
454 err = find_symbol(J, "__1cICodeBlobG__vtbl_", &J->CodeBlob_vtbl); | |
455 CHECK_FAIL(err); | |
456 err = find_symbol(J, "__1cLRuntimeStubG__vtbl_", &J->RuntimeStub_vtbl); | |
457 CHECK_FAIL(err); | |
458 | |
459 err = parse_vmstructs(J); | |
460 CHECK_FAIL(err); | |
461 err = read_volatiles(J); | |
462 CHECK_FAIL(err); | |
463 | |
464 return J; | |
465 | |
466 fail: | |
467 Jagent_destroy(J); | |
468 return NULL; | |
469 } | |
470 | |
471 void Jagent_destroy(jvm_agent_t *J) { | |
472 if (J != NULL) { | |
473 free(J); | |
474 } | |
475 } | |
476 | |
477 static int is_methodOop(jvm_agent_t* J, uint64_t methodOopPtr) { | |
478 uint64_t klass; | |
479 int err; | |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
480 // If UseCompressedOops, this was a compressed oop. |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
481 if (J->Use_Compressed_Oops != 0) { |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
482 uint32_t cklass; |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
483 err = read_compressed_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
484 &cklass); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
485 // decode heap oop, same as oop.inline.hpp |
642
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
486 klass = (uint64_t)((uintptr_t)J->Universe_narrow_oop_base + |
660978a2a31a
6791178: Specialize for zero as the compressed oop vm heap base
kvn
parents:
196
diff
changeset
|
487 ((uintptr_t)cklass << J->Universe_narrow_oop_shift)); |
113
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
488 } else { |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
489 err = read_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, &klass); |
ba764ed4b6f2
6420645: Create a vm that uses compressed oops for up to 32gb heapsizes
coleenp
parents:
0
diff
changeset
|
490 } |
0 | 491 if (err != PS_OK) goto fail; |
492 return klass == J->Universe_methodKlassObj; | |
493 | |
494 fail: | |
495 return 0; | |
496 } | |
497 | |
498 static int | |
499 name_for_methodOop(jvm_agent_t* J, uint64_t methodOopPtr, char * result, size_t size) | |
500 { | |
501 short nameIndex; | |
502 short signatureIndex; | |
503 uint64_t constantPool; | |
504 uint64_t constMethod; | |
505 uint64_t nameSymbol; | |
506 uint64_t signatureSymbol; | |
507 uint64_t klassPtr; | |
508 uint64_t klassSymbol; | |
509 short klassSymbolLength; | |
510 short nameSymbolLength; | |
511 short signatureSymbolLength; | |
512 char * nameString = NULL; | |
513 char * klassString = NULL; | |
514 char * signatureString = NULL; | |
515 int err; | |
516 | |
517 err = read_pointer(J, methodOopPtr + OFFSET_methodOopDesc_constants, &constantPool); | |
518 CHECK_FAIL(err); | |
519 err = read_pointer(J, methodOopPtr + OFFSET_methodOopDesc_constMethod, &constMethod); | |
520 CHECK_FAIL(err); | |
521 | |
522 /* To get name string */ | |
523 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_name_index, &nameIndex, 2); | |
524 CHECK_FAIL(err); | |
525 err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_constantPoolOopDesc, &nameSymbol); | |
526 CHECK_FAIL(err); | |
2344
8a3f8defe568
7019165: Incorrect symbols in pstack output after SymbolTable changes
coleenp
parents:
2177
diff
changeset
|
527 // The symbol is a CPSlot and has lower bit set to indicate metadata |
8a3f8defe568
7019165: Incorrect symbols in pstack output after SymbolTable changes
coleenp
parents:
2177
diff
changeset
|
528 nameSymbol &= (~1); // remove metadata lsb |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1748
diff
changeset
|
529 err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2); |
0 | 530 CHECK_FAIL(err); |
531 nameString = (char*)calloc(nameSymbolLength + 1, 1); | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1748
diff
changeset
|
532 err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength); |
0 | 533 CHECK_FAIL(err); |
534 | |
535 /* To get signature string */ | |
536 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_signature_index, &signatureIndex, 2); | |
537 CHECK_FAIL(err); | |
538 err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_constantPoolOopDesc, &signatureSymbol); | |
539 CHECK_FAIL(err); | |
2344
8a3f8defe568
7019165: Incorrect symbols in pstack output after SymbolTable changes
coleenp
parents:
2177
diff
changeset
|
540 signatureSymbol &= (~1); // remove metadata lsb |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1748
diff
changeset
|
541 err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2); |
0 | 542 CHECK_FAIL(err); |
543 signatureString = (char*)calloc(signatureSymbolLength + 1, 1); | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1748
diff
changeset
|
544 err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength); |
0 | 545 CHECK_FAIL(err); |
546 | |
547 /* To get klass string */ | |
548 err = read_pointer(J, constantPool + OFFSET_constantPoolOopDesc_pool_holder, &klassPtr); | |
549 CHECK_FAIL(err); | |
550 err = read_pointer(J, klassPtr + OFFSET_Klass_name + SIZE_oopDesc, &klassSymbol); | |
551 CHECK_FAIL(err); | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1748
diff
changeset
|
552 err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2); |
0 | 553 CHECK_FAIL(err); |
554 klassString = (char*)calloc(klassSymbolLength + 1, 1); | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1748
diff
changeset
|
555 err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength); |
0 | 556 CHECK_FAIL(err); |
557 | |
558 result[0] = '\0'; | |
559 strncat(result, klassString, size); | |
560 size -= strlen(klassString); | |
561 strncat(result, ".", size); | |
562 size -= 1; | |
563 strncat(result, nameString, size); | |
564 size -= strlen(nameString); | |
565 strncat(result, signatureString, size); | |
566 | |
567 if (nameString != NULL) free(nameString); | |
568 if (klassString != NULL) free(klassString); | |
569 if (signatureString != NULL) free(signatureString); | |
570 | |
571 return PS_OK; | |
572 | |
573 fail: | |
574 if (debug) { | |
575 fprintf(stderr, "name_for_methodOop: FAIL \n\n"); | |
576 } | |
577 if (nameString != NULL) free(nameString); | |
578 if (klassString != NULL) free(klassString); | |
579 if (signatureString != NULL) free(signatureString); | |
580 return -1; | |
581 } | |
582 | |
583 static int nmethod_info(Nmethod_t *N) | |
584 { | |
585 jvm_agent_t *J = N->J; | |
586 uint64_t nm = N->nm; | |
587 int32_t err; | |
588 | |
589 if (debug > 2 ) | |
590 fprintf(stderr, "\t nmethod_info: BEGIN \n"); | |
591 | |
592 /* Instructions */ | |
1748 | 593 err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32); |
0 | 594 CHECK_FAIL(err); |
595 err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32); | |
596 CHECK_FAIL(err); | |
597 err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32); | |
598 CHECK_FAIL(err); | |
599 err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32); | |
600 CHECK_FAIL(err); | |
601 | |
602 /* Oops */ | |
1563
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
603 err = ps_pread(J->P, nm + OFFSET_nmethod_oops_offset, &N->oops_beg, SZ32); |
0 | 604 CHECK_FAIL(err); |
1563
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
605 err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->oops_end, SZ32); |
0 | 606 CHECK_FAIL(err); |
607 | |
608 /* scopes_pcs */ | |
609 err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32); | |
610 CHECK_FAIL(err); | |
611 err = ps_pread(J->P, nm + OFFSET_nmethod_handler_table_offset, &N->scopes_pcs_end, SZ32); | |
612 CHECK_FAIL(err); | |
613 | |
614 /* scopes_data */ | |
615 err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32); | |
616 CHECK_FAIL(err); | |
617 | |
618 if (debug > 2 ) { | |
619 N->scopes_data_end = N->scopes_pcs_beg; | |
620 | |
621 fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n", | |
622 N->instrs_beg, N->instrs_end); | |
623 | |
624 fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n", | |
625 N->deopt_beg); | |
626 | |
627 fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n", | |
628 N->orig_pc_offset); | |
629 | |
1563
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
630 fprintf(stderr, "\t nmethod_info: oops_beg: %#x, oops_end: %#x\n", |
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
631 N->oops_beg, N->oops_end); |
0 | 632 |
633 fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n", | |
634 N->scopes_data_beg, N->scopes_data_end); | |
635 | |
636 fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n", | |
637 N->scopes_pcs_beg, N->scopes_pcs_end); | |
638 | |
639 fprintf(stderr, "\t nmethod_info: END \n\n"); | |
640 } | |
641 return PS_OK; | |
642 | |
643 fail: | |
644 return err; | |
645 } | |
646 | |
647 static int | |
648 raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val) | |
649 { | |
650 int shift = 0; | |
651 int value = 0; | |
652 uint8_t ch = 0; | |
653 int32_t err; | |
654 int32_t sum; | |
655 // Constants for UNSIGNED5 coding of Pack200 | |
656 // see compressedStream.hpp | |
657 enum { | |
658 lg_H = 6, | |
659 H = 1<<lg_H, | |
660 BitsPerByte = 8, | |
661 L = (1<<BitsPerByte)-H, | |
662 }; | |
663 int i; | |
664 | |
665 err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); | |
666 CHECK_FAIL(err); | |
667 if (debug > 2) | |
668 fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch); | |
669 | |
670 sum = ch; | |
671 if ( sum >= L ) { | |
672 int32_t lg_H_i = lg_H; | |
673 // Read maximum of 5 total bytes (we've already read 1). | |
674 // See CompressedReadStream::read_int_mb | |
675 for ( i = 0; i < 4; i++) { | |
676 err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); | |
677 CHECK_FAIL(err); | |
678 sum += ch << lg_H_i; | |
679 if (ch < L ) { | |
680 *val = sum; | |
681 return PS_OK; | |
682 } | |
683 lg_H_i += lg_H; | |
684 } | |
685 } | |
686 *val = sum; | |
687 return PS_OK; | |
688 | |
689 fail: | |
690 return err; | |
691 } | |
692 | |
693 static int | |
694 read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line) | |
695 { | |
696 uint8_t next = 0; | |
697 int32_t bci_delta; | |
698 int32_t line_delta; | |
699 int32_t err; | |
700 | |
701 if (debug > 2) | |
702 fprintf(stderr, "\t\t read_pair: BEGIN\n"); | |
703 | |
704 err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t)); | |
705 CHECK_FAIL(err); | |
706 | |
707 if (next == 0) { | |
708 if (debug > 2) | |
709 fprintf(stderr, "\t\t read_pair: END: next == 0\n"); | |
710 return 1; /* stream terminated */ | |
711 } | |
712 if (next == 0xFF) { | |
713 if (debug > 2) | |
714 fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n"); | |
715 | |
716 /* Escape character, regular compression used */ | |
717 | |
718 err = raw_read_int(J, buffer, &bci_delta); | |
719 CHECK_FAIL(err); | |
720 | |
721 err = raw_read_int(J, buffer, &line_delta); | |
722 CHECK_FAIL(err); | |
723 | |
724 *bci += bci_delta; | |
725 *line += line_delta; | |
726 | |
727 if (debug > 2) { | |
728 fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", | |
729 line_delta, bci_delta); | |
730 fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", | |
731 *line, *bci); | |
732 } | |
733 } else { | |
734 /* Single byte compression used */ | |
735 *bci += next >> 3; | |
736 *line += next & 0x7; | |
737 if (debug > 2) { | |
738 fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", | |
739 next & 0x7, next >> 3); | |
740 fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", | |
741 *line, *bci); | |
742 } | |
743 } | |
744 if (debug > 2) | |
745 fprintf(stderr, "\t\t read_pair: END\n"); | |
746 return PS_OK; | |
747 | |
748 fail: | |
749 if (debug) | |
750 fprintf(stderr, "\t\t read_pair: FAIL\n"); | |
751 return err; | |
752 } | |
753 | |
754 static int | |
755 line_number_from_bci(jvm_agent_t* J, Vframe_t *vf) | |
756 { | |
757 uint64_t buffer; | |
758 uint16_t code_size; | |
759 uint64_t code_end_delta; | |
760 uint64_t constMethod; | |
761 int8_t access_flags; | |
762 int32_t best_bci = 0; | |
763 int32_t stream_bci = 0; | |
764 int32_t stream_line = 0; | |
765 int32_t err; | |
766 | |
767 if (debug > 2) { | |
768 char name[256]; | |
769 err = name_for_methodOop(J, vf->methodOop, name, 256); | |
770 CHECK_FAIL(err); | |
771 fprintf(stderr, "\t line_number_from_bci: BEGIN, method name: %s, targ bci: %d\n", | |
772 name, vf->bci); | |
773 } | |
774 | |
775 err = read_pointer(J, vf->methodOop + OFFSET_methodOopDesc_constMethod, &constMethod); | |
776 CHECK_FAIL(err); | |
777 | |
778 vf->line = 0; | |
779 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_flags, &access_flags, sizeof(int8_t)); | |
780 CHECK_FAIL(err); | |
781 | |
782 if (!(access_flags & constMethodOopDesc_has_linenumber_table)) { | |
783 if (debug > 2) | |
784 fprintf(stderr, "\t line_number_from_bci: END: !HAS_LINE_NUMBER_TABLE \n\n"); | |
785 return PS_OK; | |
786 } | |
787 | |
788 /* The line numbers are a short array of 2-tuples [start_pc, line_number]. | |
789 * Not necessarily sorted and not necessarily one-to-one. | |
790 */ | |
791 | |
792 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_code_size, &code_size, SZ16); | |
793 CHECK_FAIL(err); | |
794 | |
795 /* inlined_table_start() */ | |
796 code_end_delta = (uint64_t) (access_flags & AccessFlags_NATIVE) ? 2*POINTER_SIZE : 0; | |
797 buffer = constMethod + (uint64_t) SIZE_constMethodOopDesc + (uint64_t) code_size + code_end_delta; | |
798 | |
799 if (debug > 2) { | |
800 fprintf(stderr, "\t\t line_number_from_bci: methodOop: %#llx, native: %d\n", | |
801 vf->methodOop, (access_flags & AccessFlags_NATIVE)); | |
802 fprintf(stderr, "\t\t line_number_from_bci: buffer: %#llx, code_size: %d\n", | |
803 buffer, (int) code_size); | |
804 } | |
805 | |
806 while (read_pair(J, &buffer, &stream_bci, &stream_line) == 0) { | |
807 if (stream_bci == vf->bci) { | |
808 /* perfect match */ | |
809 if (debug > 2) | |
810 fprintf(stderr, "\t line_number_from_bci: END: exact line: %ld \n\n", vf->line); | |
811 vf->line = stream_line; | |
812 return PS_OK; | |
813 } else { | |
814 /* update best_bci/line */ | |
815 if (stream_bci < vf->bci && stream_bci >= best_bci) { | |
816 best_bci = stream_bci; | |
817 vf->line = stream_line; | |
818 if (debug > 2) { | |
819 fprintf(stderr, "\t line_number_from_bci: best_bci: %ld, best_line: %ld\n", | |
820 best_bci, vf->line); | |
821 } | |
822 } | |
823 } | |
824 } | |
825 if (debug > 2) | |
826 fprintf(stderr, "\t line_number_from_bci: END: line: %ld \n\n", vf->line); | |
827 return PS_OK; | |
828 | |
829 fail: | |
830 if (debug) | |
831 fprintf(stderr, "\t line_number_from_bci: FAIL\n"); | |
832 return err; | |
833 } | |
834 | |
835 static int | |
836 get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc) | |
837 { | |
838 int32_t pc_offset; | |
839 int32_t err; | |
840 | |
841 err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32); | |
842 CHECK_FAIL(err); | |
843 | |
844 *real_pc = N->nm + N->instrs_beg + pc_offset; | |
845 if (debug > 2) { | |
846 fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n", | |
847 pc_offset, *real_pc); | |
848 } | |
849 return PS_OK; | |
850 | |
851 fail: | |
852 return err; | |
853 } | |
854 | |
855 /* Finds a PcDesc with real-pc equal to N->pc */ | |
856 static int pc_desc_at(Nmethod_t *N) | |
857 { | |
858 uint64_t pc_diff; | |
859 int32_t offs; | |
860 int32_t err; | |
861 | |
862 if (debug > 2) | |
863 fprintf(stderr, "\t pc_desc_at: BEGIN\n"); | |
864 | |
865 N->vf_cnt = 0; | |
866 N->pc_desc = 0; | |
867 | |
868 for (offs = N->scopes_pcs_beg; offs < N->scopes_pcs_end; offs += SIZE_PcDesc) { | |
869 uint64_t pd; | |
870 uint64_t best_pc_diff = 16; /* some approximation */ | |
871 uint64_t real_pc = 0; | |
872 | |
873 pd = N->nm + offs; | |
874 err = get_real_pc(N, pd, &real_pc); | |
875 CHECK_FAIL(err); | |
876 | |
877 pc_diff = real_pc - N->pc; | |
878 | |
879 /* In general, this fragment should work */ | |
880 if (pc_diff == 0) { | |
881 N->pc_desc = pd; | |
882 if (debug) { | |
883 fprintf(stderr, "\t pc_desc_at: END: pc_desc: FOUND: %#lx \n\n", pd); | |
884 } | |
885 return PS_OK; | |
886 } | |
887 /* This fragment is to be able to find out an appropriate | |
888 * pc_desc entry even if pc_desc info is inaccurate. | |
889 */ | |
890 if (best_pc_diff > pc_diff && pc_diff > 0) { | |
891 best_pc_diff = pc_diff; | |
892 N->pc_desc = pd; | |
893 } | |
894 } | |
895 if (debug) { | |
896 fprintf(stderr, "\t pc_desc_at: END: pc_desc NOT FOUND"); | |
897 if (pc_diff < 20) | |
898 fprintf(stderr, ", best pc_diff: %d\n\n", pc_diff); | |
899 else | |
900 fprintf(stderr, "\n\n"); | |
901 } | |
902 return PS_OK; | |
903 | |
904 fail: | |
905 return err; | |
906 } | |
907 | |
908 static int | |
909 scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf) | |
910 { | |
911 uint64_t buffer; | |
912 int32_t err; | |
913 | |
914 if (debug > 2) { | |
915 fprintf(stderr, "\t\t scope_desc_at: BEGIN \n"); | |
916 } | |
917 | |
918 buffer = N->nm + N->scopes_data_beg + decode_offset; | |
919 | |
920 err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset); | |
921 CHECK_FAIL(err); | |
922 | |
923 err = raw_read_int(N->J, &buffer, &vf->methodIdx); | |
924 CHECK_FAIL(err); | |
925 | |
926 err = raw_read_int(N->J, &buffer, &vf->bci); | |
927 CHECK_FAIL(err); | |
928 | |
929 if (debug > 2) { | |
930 fprintf(stderr, "\t\t scope_desc_at: sender_decode_offset: %#x\n", | |
931 vf->sender_decode_offset); | |
932 fprintf(stderr, "\t\t scope_desc_at: methodIdx: %d\n", vf->methodIdx); | |
933 fprintf(stderr, "\t\t scope_desc_at: bci: %d\n", vf->bci); | |
934 | |
935 fprintf(stderr, "\t\t scope_desc_at: END \n\n"); | |
936 } | |
937 return PS_OK; | |
938 | |
939 fail: | |
940 return err; | |
941 } | |
942 | |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
943 static int scopeDesc_chain(Nmethod_t *N) { |
0 | 944 int32_t decode_offset = 0; |
945 int32_t err; | |
946 | |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
947 if (debug > 2) { |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
948 fprintf(stderr, "\t scopeDesc_chain: BEGIN\n"); |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
949 } |
0 | 950 |
951 err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset, | |
952 &decode_offset, SZ32); | |
953 CHECK_FAIL(err); | |
954 | |
955 while (decode_offset > 0) { | |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
956 Vframe_t *vf = &N->vframes[N->vf_cnt]; |
0 | 957 |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
958 if (debug > 2) { |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
959 fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset); |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
960 } |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
961 |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
962 err = scope_desc_at(N, decode_offset, vf); |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
963 CHECK_FAIL(err); |
0 | 964 |
1563
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
965 if (vf->methodIdx > ((N->oops_end - N->oops_beg) / POINTER_SIZE)) { |
1a5913bf5e19
6951083: oops and relocations should part of nmethod not CodeBlob
twisti
parents:
1123
diff
changeset
|
966 fprintf(stderr, "\t scopeDesc_chain: (methodIdx > oops length) !\n"); |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
967 return -1; |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
968 } |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
969 err = read_pointer(N->J, N->nm + N->oops_beg + (vf->methodIdx-1)*POINTER_SIZE, |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
970 &vf->methodOop); |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
971 CHECK_FAIL(err); |
0 | 972 |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
973 if (vf->methodOop) { |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
974 N->vf_cnt++; |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
975 err = line_number_from_bci(N->J, vf); |
0 | 976 CHECK_FAIL(err); |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
977 if (debug > 2) { |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
978 fprintf(stderr, "\t scopeDesc_chain: methodOop: %#8llx, line: %ld\n", |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
979 vf->methodOop, vf->line); |
0 | 980 } |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
981 } |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
982 decode_offset = vf->sender_decode_offset; |
0 | 983 } |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
984 if (debug > 2) { |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
985 fprintf(stderr, "\t scopeDesc_chain: END \n\n"); |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
986 } |
0 | 987 return PS_OK; |
988 | |
989 fail: | |
1123
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
990 if (debug) { |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
991 fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n"); |
167c2986d91b
6843629: Make current hotspot build part of jdk5 control build
phh
parents:
844
diff
changeset
|
992 } |
0 | 993 return err; |
994 } | |
995 | |
996 | |
997 static int | |
998 name_for_nmethod(jvm_agent_t* J, | |
999 uint64_t nm, | |
1000 uint64_t pc, | |
1001 uint64_t methodOop, | |
1002 char *result, | |
1003 size_t size, | |
1004 Jframe_t *jframe | |
1005 ) { | |
1006 Nmethod_t *N; | |
1007 Vframe_t *vf; | |
1008 int32_t err; | |
1009 int deoptimized = 0; | |
1010 | |
1011 if (debug) { | |
1012 fprintf(stderr, "name_for_nmethod: BEGIN: nmethod: %#llx, pc: %#llx\n", nm, pc); | |
1013 } | |
1014 if (J->N == NULL) { | |
1015 J->N = (Nmethod_t *) malloc(sizeof(Nmethod_t)); | |
1016 } | |
1017 memset(J->N, 0, sizeof(Nmethod_t)); /* Initial stat: all values are zeros */ | |
1018 N = J->N; | |
1019 N->J = J; | |
1020 N->nm = nm; | |
1021 N->pc = pc; | |
1022 N->jframe = jframe; | |
1023 | |
1024 err = nmethod_info(N); | |
1025 CHECK_FAIL(err); | |
1026 if (debug) { | |
1027 fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n", | |
1028 pc, N->nm + N->deopt_beg); | |
1029 } | |
1030 | |
1031 /* check for a deoptimized frame */ | |
1032 if ( pc == N->nm + N->deopt_beg) { | |
1033 uint64_t base; | |
1034 if (debug) { | |
1035 fprintf(stderr, "name_for_nmethod: found deoptimized frame\n"); | |
1036 } | |
1037 if (J->prev_fr.sender_sp != 0) { | |
1038 base = J->prev_fr.sender_sp + N->orig_pc_offset; | |
1039 } else { | |
1040 base = J->curr_fr.sp + N->orig_pc_offset; | |
1041 } | |
1042 err = read_pointer(J, base, &N->pc); | |
1043 CHECK_FAIL(err); | |
1044 if (debug) { | |
1045 fprintf(stderr, "name_for_nmethod: found deoptimized frame converting pc from %#8llx to %#8llx\n", | |
1046 pc, N->pc); | |
1047 } | |
1048 deoptimized = 1; | |
1049 } | |
1050 | |
1051 err = pc_desc_at(N); | |
1052 CHECK_FAIL(err); | |
1053 | |
1054 if (N->pc_desc > 0) { | |
1055 jframe->locinf = 1; | |
1056 err = scopeDesc_chain(N); | |
1057 CHECK_FAIL(err); | |
1058 } | |
1059 result[0] = COMP_METHOD_SIGN; | |
1060 vf = &N->vframes[0]; | |
1061 if (N->vf_cnt > 0) { | |
1062 jframe->vf_cnt = N->vf_cnt; | |
1063 jframe->bci = vf->bci; | |
1064 jframe->line = vf->line; | |
1065 err = name_for_methodOop(J, N->vframes[0].methodOop, result+1, size-1); | |
1066 CHECK_FAIL(err); | |
1067 } else { | |
1068 err = name_for_methodOop(J, methodOop, result+1, size-1); | |
1069 CHECK_FAIL(err); | |
1070 } | |
1071 if (deoptimized) { | |
1072 strncat(result + 1, " [deoptimized frame]; ", size-1); | |
1073 } else { | |
1074 strncat(result + 1, " [compiled] ", size-1); | |
1075 } | |
1076 if (debug) | |
1077 fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n", | |
1078 result, N->vf_cnt); | |
1079 return PS_OK; | |
1080 | |
1081 fail: | |
1082 if (debug) | |
1083 fprintf(stderr, "name_for_nmethod: FAIL \n\n"); | |
1084 return err; | |
1085 } | |
1086 | |
1087 int is_bci(intptr_t bcx) { | |
1088 switch (DATA_MODEL) { | |
1089 case PR_MODEL_LP64: | |
1090 return ((uintptr_t) bcx) <= ((uintptr_t) MAX_METHOD_CODE_SIZE) ; | |
1091 case PR_MODEL_ILP32: | |
1092 default: | |
1093 return 0 <= bcx && bcx <= MAX_METHOD_CODE_SIZE; | |
1094 } | |
1095 } | |
1096 | |
1097 static int | |
1098 name_for_imethod(jvm_agent_t* J, | |
1099 uint64_t bcx, | |
1100 uint64_t methodOop, | |
1101 char *result, | |
1102 size_t size, | |
1103 Jframe_t *jframe | |
1104 ) { | |
1105 uint64_t bci; | |
1106 uint64_t constMethod; | |
1107 Vframe_t vframe = {0}; | |
1108 Vframe_t *vf = &vframe; | |
1109 int32_t err; | |
1110 | |
1111 err = read_pointer(J, methodOop + OFFSET_methodOopDesc_constMethod, &constMethod); | |
1112 CHECK_FAIL(err); | |
1113 | |
1114 bci = is_bci(bcx) ? bcx : bcx - (constMethod + (uint64_t) SIZE_constMethodOopDesc); | |
1115 | |
1116 if (debug) | |
1117 fprintf(stderr, "\t name_for_imethod: BEGIN: methodOop: %#llx\n", methodOop); | |
1118 | |
1119 err = name_for_methodOop(J, methodOop, result, size); | |
1120 CHECK_FAIL(err); | |
1121 if (debug) | |
1122 fprintf(stderr, "\t name_for_imethod: method name: %s\n", result); | |
1123 | |
1124 if (bci > 0) { | |
1125 vf->methodOop = methodOop; | |
1126 vf->bci = bci; | |
1127 err = line_number_from_bci(J, vf); | |
1128 CHECK_FAIL(err); | |
1129 } | |
1130 jframe->bci = vf->bci; | |
1131 jframe->line = vf->line; | |
1132 jframe->locinf = 1; | |
1133 | |
1134 if (debug) { | |
1135 fprintf(stderr, "\t name_for_imethod: END: bci: %d, line: %d\n\n", | |
1136 vf->bci, vf->line); | |
1137 } | |
1138 return PS_OK; | |
1139 | |
1140 fail: | |
1141 if (debug) | |
1142 fprintf(stderr, "\t name_for_imethod: FAIL\n"); | |
1143 return err; | |
1144 } | |
1145 | |
1146 static int | |
1147 name_for_codecache(jvm_agent_t* J, uint64_t fp, uint64_t pc, char * result, | |
1148 size_t size, Jframe_t *jframe, int* is_interpreted) | |
1149 { | |
1150 uint64_t start; | |
1151 uint64_t vtbl; | |
1152 int32_t err; | |
1153 *is_interpreted = 0; | |
1154 | |
1155 result[0] = '\0'; | |
1156 | |
1157 err = find_start(J, pc, &start); | |
1158 CHECK_FAIL(err); | |
1159 | |
1160 err = read_pointer(J, start, &vtbl); | |
1161 CHECK_FAIL(err); | |
1162 | |
1163 if (vtbl == J->nmethod_vtbl) { | |
1164 uint64_t methodOop; | |
1165 | |
1166 err = read_pointer(J, start + OFFSET_nmethod_method, &methodOop); | |
1167 CHECK_FAIL(err); | |
1168 | |
1169 if (debug) { | |
1170 fprintf(stderr, "name_for_codecache: start: %#8llx, pc: %#8llx, methodOop: %#8llx \n", | |
1171 start, pc, methodOop); | |
1172 } | |
1173 err = name_for_nmethod(J, start, pc, methodOop, result, size, jframe); | |
1174 CHECK_FAIL(err); | |
1175 } else if (vtbl == J->BufferBlob_vtbl) { | |
1176 const char * name; | |
1177 | |
1178 err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name); | |
1179 | |
1180 /* | |
1181 * Temporary usage of string "Interpreter". | |
1182 * We need some other way to distinguish "StubRoutines" | |
1183 * and regular interpreted frames. | |
1184 */ | |
1185 if (err == PS_OK && strncmp(name, "Interpreter", 11) == 0) { | |
1186 *is_interpreted = 1; | |
1187 if (is_methodOop(J, J->methodOopPtr)) { | |
1188 return name_for_imethod(J, J->bcx, J->methodOopPtr, result, size, jframe); | |
1189 } | |
1190 } | |
1191 | |
1192 if (err == PS_OK) { | |
1193 strncpy(result, name, size); | |
1194 free((void*)name); | |
1195 } else { | |
1196 strncpy(result, "<unknown BufferBlob>", size); | |
1197 } | |
1198 /* return PS_OK; */ | |
1199 } else { | |
1200 const char * name; | |
1201 | |
1202 err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name); | |
1203 if (err == PS_OK) { | |
1204 strncpy(result, name, size); | |
1205 free((void*)name); | |
1206 } else { | |
1207 strncpy(result, "<unknown CodeBlob>", size); | |
1208 WARN1("unknown CodeBlob: vtbl = 0x%x", vtbl); | |
1209 } | |
1210 } | |
1211 result[size-1] = '\0'; | |
1212 | |
1213 #ifdef X86_COMPILER2 | |
1214 if (vtbl != J->RuntimeStub_vtbl) { | |
1215 uint64_t trial_pc; | |
1216 int frame_size; | |
1217 err = ps_pread(J->P, start + OFFSET_CodeBlob_frame_size, | |
1218 &frame_size, SZ32); | |
1219 CHECK_FAIL(err); | |
1220 | |
1221 // frame_size is in words, we want bytes. | |
1222 frame_size *= POINTER_SIZE; /* word => byte conversion */ | |
1223 | |
1224 /* | |
1225 Because c2 doesn't use FP as a framepointer the value of sp/fp we receive | |
1226 in the initial entry to a set of stack frames containing server frames | |
1227 will pretty much be nonsense. We can detect that nonsense by looking to | |
1228 see if the PC we received is correct if we look at the expected storage | |
1229 location in relation to the FP (ie. POINTER_SIZE(FP) ) | |
1230 */ | |
1231 | |
1232 err = read_pointer(J, fp + POINTER_SIZE , &trial_pc); | |
1233 if ( (err != PS_OK || trial_pc != pc) && frame_size > 0 ) { | |
1234 // Either we couldn't even read at the "fp" or the pc didn't match | |
1235 // both are sure clues that the fp is bogus. We no search the stack | |
1236 // for a reasonable number of words trying to find the bogus fp | |
1237 // and the current pc in adjacent words. The we will be able to | |
1238 // deduce an approximation of the frame pointer and actually get | |
1239 // the correct stack pointer. Which we can then unwind for the | |
1240 // next frame. | |
1241 int i; | |
1242 uint64_t check; | |
1243 uint64_t base = J->curr_fr.sp; | |
1244 uint64_t prev_fp = 0; | |
1245 for ( i = 0; i < frame_size * 5 ; i++, base += POINTER_SIZE ) { | |
1246 err = read_pointer(J, base , &check); | |
1247 CHECK_FAIL(err); | |
1248 if (check == fp) { | |
1249 base += POINTER_SIZE; | |
1250 err = read_pointer(J, base , &check); | |
1251 CHECK_FAIL(err); | |
1252 if (check == pc) { | |
1253 if (debug) { | |
1254 fprintf(stderr, "name_for_codecache: found matching fp/pc combo at 0x%llx\n", base - POINTER_SIZE); | |
1255 } | |
1256 prev_fp = base - 2 * POINTER_SIZE; | |
1257 break; | |
1258 } | |
1259 } | |
1260 } | |
1261 if ( prev_fp != 0 ) { | |
1262 // real_sp is the sp we should have received for this frame | |
1263 uint64_t real_sp = prev_fp + 2 * POINTER_SIZE; | |
1264 // +POINTER_SIZE because callee owns the return address so caller's sp is +1 word | |
1265 jframe->new_sp = real_sp + frame_size + POINTER_SIZE; | |
1266 err = read_pointer(J, jframe->new_sp - POINTER_SIZE , &jframe->new_pc); | |
1267 CHECK_FAIL(err); | |
1268 err = read_pointer(J, jframe->new_sp - 2*POINTER_SIZE, &jframe->new_fp); | |
1269 CHECK_FAIL(err); | |
1270 return PS_OK; | |
1271 } | |
1272 } | |
1273 | |
1274 /* A prototype to workaround FP absence */ | |
1275 /* | |
1276 * frame_size can be 0 for StubRoutines (1) frame. | |
1277 * In this case it should work with fp as usual. | |
1278 */ | |
1279 if (frame_size > 0) { | |
1280 jframe->new_fp = J->prev_fr.fp + frame_size; | |
1281 jframe->new_sp = jframe->new_fp + 2 * POINTER_SIZE; | |
1282 } else { | |
1283 memset(&J->curr_fr, 0, sizeof(Frame_t)); | |
1284 err = read_pointer(J, fp, &jframe->new_fp); | |
1285 CHECK_FAIL(err); | |
1286 | |
1287 err = read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc); | |
1288 CHECK_FAIL(err); | |
1289 } | |
1290 if (debug) { | |
1291 fprintf(stderr, "name_for_codecache: %s, frame_size=%#lx\n", | |
1292 result, frame_size); | |
1293 fprintf(stderr, "name_for_codecache: prev_fr.fp=%#lx, fp=%#lx\n", | |
1294 J->prev_fr.fp, jframe->new_fp); | |
1295 } | |
1296 } | |
1297 #endif /* X86_COMPILER2 */ | |
1298 | |
1299 return PS_OK; | |
1300 | |
1301 fail: | |
1302 return err; | |
1303 } | |
1304 | |
1305 int Jget_vframe(jvm_agent_t* J, int vframe_no, | |
1306 char *name, size_t size, Jframe_t *jframe) | |
1307 { | |
1308 Nmethod_t *N = J->N; | |
1309 Vframe_t *vf; | |
1310 int32_t err; | |
1311 | |
1312 if (vframe_no >= N->vf_cnt) { | |
1313 (void) sprintf(name, "Wrong inlinedMethod%1d()", vframe_no); | |
1314 return -1; | |
1315 } | |
1316 vf = N->vframes + vframe_no; | |
1317 name[0] = COMP_METHOD_SIGN; | |
1318 err = name_for_methodOop(J, vf->methodOop, name + 1, size); | |
1319 CHECK_FAIL(err); | |
1320 | |
1321 jframe->bci = vf->bci; | |
1322 jframe->line = vf->line; | |
1323 if (debug) { | |
1324 fprintf(stderr, "\t Jget_vframe: method name: %s, line: %ld\n", | |
1325 name, vf->line); | |
1326 } | |
1327 return PS_OK; | |
1328 | |
1329 fail: | |
1330 if (debug) { | |
1331 fprintf(stderr, "\t Jget_vframe: FAIL\n"); | |
1332 } | |
1333 return err; | |
1334 } | |
1335 | |
1336 #define MAX_SYM_SIZE 256 | |
1337 | |
1338 int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name, | |
1339 size_t size, Jframe_t *jframe) { | |
1340 uintptr_t fp; | |
1341 uintptr_t pc; | |
1342 /* arguments given to read_pointer need to be worst case sized */ | |
1343 uint64_t methodOopPtr = 0; | |
1344 uint64_t sender_sp; | |
1345 uint64_t bcx = 0; | |
1346 int is_interpreted = 0; | |
1347 int result = PS_OK; | |
1348 int err = PS_OK; | |
1349 | |
1350 if (J == NULL) { | |
1351 return -1; | |
1352 } | |
1353 | |
1354 jframe->vf_cnt = 1; | |
1355 jframe->new_fp = 0; | |
1356 jframe->new_pc = 0; | |
1357 jframe->line = 0; | |
1358 jframe->bci = 0; | |
1359 jframe->locinf = 0; | |
1360 | |
1361 read_volatiles(J); | |
1362 pc = (uintptr_t) regs[R_PC]; | |
1363 J->curr_fr.pc = pc; | |
1364 J->curr_fr.fp = regs[R_FP]; | |
1365 J->curr_fr.sp = regs[R_SP]; | |
1366 | |
1367 if (debug) | |
1368 fprintf(stderr, "Jlookup_by_regs: BEGINs: fp=%#lx, pc=%#lx\n", regs[R_FP], pc); | |
1369 | |
1370 #if defined(sparc) || defined(__sparc) | |
1371 /* The following workaround is for SPARC. CALL instruction occupates 8 bytes. | |
1372 * In the pcDesc structure return pc offset is recorded for CALL instructions. | |
1373 * regs[R_PC] contains a CALL instruction pc offset. | |
1374 */ | |
1375 pc += 8; | |
1376 bcx = (uintptr_t) regs[R_L1]; | |
1377 methodOopPtr = (uintptr_t) regs[R_L2]; | |
1378 sender_sp = regs[R_I5]; | |
1379 if (debug > 2) { | |
1380 fprintf(stderr, "\nregs[R_I1]=%lx, regs[R_I2]=%lx, regs[R_I5]=%lx, regs[R_L1]=%lx, regs[R_L2]=%lx\n", | |
1381 regs[R_I1], regs[R_I2], regs[R_I5], regs[R_L1], regs[R_L2]); | |
1382 } | |
1383 #elif defined(i386) || defined(__i386) || defined(__amd64) | |
1384 | |
1385 fp = (uintptr_t) regs[R_FP]; | |
1386 if (J->prev_fr.fp == 0) { | |
1387 #ifdef X86_COMPILER2 | |
1388 /* A workaround for top java frames */ | |
1389 J->prev_fr.fp = (uintptr_t)(regs[R_SP] - 2 * POINTER_SIZE); | |
1390 #else | |
1391 J->prev_fr.fp = (uintptr_t)(regs[R_SP] - POINTER_SIZE); | |
1392 #endif /* COMPILER2 */ | |
1393 } | |
1394 if (debug > 2) { | |
1395 printf("Jlookup_by_regs: J->prev_fr.fp = %#lx\n", J->prev_fr.fp); | |
1396 } | |
1397 | |
1398 if (read_pointer(J, fp + OFFSET_interpreter_frame_method, &methodOopPtr) != PS_OK) { | |
1399 methodOopPtr = 0; | |
1400 } | |
1401 if (read_pointer(J, fp + OFFSET_interpreter_frame_sender_sp, &sender_sp) != PS_OK) { | |
1402 sender_sp = 0; | |
1403 } | |
1404 if (read_pointer(J, fp + OFFSET_interpreter_frame_bcx_offset, &bcx) != PS_OK) { | |
1405 bcx = 0; | |
1406 } | |
1407 #endif /* i386 */ | |
1408 | |
1409 J->methodOopPtr = methodOopPtr; | |
1410 J->bcx = bcx; | |
1411 | |
1412 /* On x86 with C2 JVM: native frame may have wrong regs[R_FP] | |
1413 * For example: JVM_SuspendThread frame poins to the top interpreted frame. | |
1414 * If we call is_methodOop(J, methodOopPtr) before codecache_contains(J, pc) | |
1415 * then we go over and omit both: nmethod and I2CAdapter frames. | |
1416 * Note, that regs[R_PC] is always correct if frame defined correctly. | |
1417 * So it is better to call codecache_contains(J, pc) from the beginning. | |
1418 */ | |
1419 #ifndef X86_COMPILER2 | |
1420 if (is_methodOop(J, J->methodOopPtr)) { | |
1421 result = name_for_imethod(J, bcx, J->methodOopPtr, name, size, jframe); | |
1422 /* If the methodOopPtr is a method then this is highly likely to be | |
1423 an interpreter frame */ | |
1424 if (result >= 0) { | |
1425 is_interpreted = 1; | |
1426 } | |
1427 } else | |
1428 #endif /* ! X86_COMPILER2 */ | |
1429 | |
1430 if (codecache_contains(J, pc)) { | |
1431 result = name_for_codecache(J, fp, pc, name, size, jframe, &is_interpreted); | |
1432 } | |
1433 #ifdef X86_COMPILER2 | |
1434 else if (is_methodOop(J, J->methodOopPtr)) { | |
1435 result = name_for_imethod(J, bcx, J->methodOopPtr, name, size, jframe); | |
1436 /* If the methodOopPtr is a method then this is highly likely to be | |
1437 an interpreter frame */ | |
1438 if (result >= 0) { | |
1439 is_interpreted = 1; | |
1440 } | |
1441 } | |
1442 #endif /* X86_COMPILER2 */ | |
1443 else { | |
1444 if (debug) { | |
1445 fprintf(stderr, "Jlookup_by_regs: END with -1\n\n"); | |
1446 } | |
1447 result = -1; | |
1448 } | |
1449 if (!is_interpreted) { | |
1450 sender_sp = 0; | |
1451 } | |
1452 J->curr_fr.sender_sp = sender_sp; | |
1453 | |
1454 #ifdef X86_COMPILER2 | |
1455 if (!J->curr_fr.fp) { | |
1456 J->curr_fr.fp = (jframe->new_fp) ? jframe->new_fp : (uintptr_t)regs[R_FP]; | |
1457 } | |
1458 if (!jframe->new_pc && jframe->new_fp) { | |
1459 // This seems dubious | |
1460 read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc); | |
1461 CHECK_FAIL(err); | |
1462 if (debug > 2) { | |
1463 printf("Jlookup_by_regs: (update pc) jframe->new_fp: %#llx, jframe->new_pc: %#llx\n", | |
1464 jframe->new_fp, jframe->new_pc); | |
1465 } | |
1466 } | |
1467 | |
1468 #endif /* X86_COMPILER2 */ | |
1469 J->prev_fr = J->curr_fr; | |
1470 | |
1471 if (debug) | |
1472 fprintf(stderr, "Jlookup_by_regs: END\n\n"); | |
1473 | |
1474 return result; | |
1475 | |
1476 fail: | |
1477 return err; | |
1478 } | |
1479 | |
1480 void update_gregs(prgregset_t gregs, Jframe_t jframe) { | |
1481 #ifdef X86_COMPILER2 | |
1482 if (debug > 0) { | |
1483 fprintf(stderr, "update_gregs: before update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); | |
1484 } | |
1485 /* | |
1486 * A workaround for java C2 frames with unconventional FP. | |
1487 * may have to modify regset with new values for FP/PC/SP when needed. | |
1488 */ | |
1489 if (jframe.new_sp) { | |
1490 *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) jframe.new_sp; | |
1491 } else { | |
1492 // *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) gregs[R_FP] + 2 * POINTER_SIZE; | |
1493 } | |
1494 | |
1495 if (jframe.new_fp) { | |
1496 *((uintptr_t *) &gregs[R_FP]) = (uintptr_t) jframe.new_fp; | |
1497 } | |
1498 if (jframe.new_pc) { | |
1499 *((uintptr_t *) &gregs[R_PC]) = (uintptr_t) jframe.new_pc; | |
1500 } | |
1501 if (debug > 0) { | |
1502 fprintf(stderr, "update_gregs: after update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); | |
1503 } | |
1504 #endif /* X86_COMPILER2 */ | |
1505 } | |
1506 | |
1507 /* | |
1508 * Iterates over java frames at current location given by 'gregs'. | |
1509 * | |
1510 * Returns -1 if no java frames are present or if an error is encountered. | |
1511 * Returns the result of calling 'func' if the return value is non-zero. | |
1512 * Returns 0 otherwise. | |
1513 */ | |
1514 int Jframe_iter(jvm_agent_t *J, prgregset_t gregs, java_stack_f *func, void* cld) { | |
1515 char buf[MAX_SYM_SIZE + 1]; | |
1516 Jframe_t jframe; | |
1517 int i = 0, res; | |
1518 #ifdef X86_COMPILER2 | |
1519 if (debug > 0) { | |
1520 fprintf(stderr, "Jframe_iter: Entry sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); | |
1521 } | |
1522 #endif /* X86_COMPILER2 */ | |
1523 | |
1524 memset(&jframe, 0, sizeof(Jframe_t)); | |
1525 memset(buf, 0, sizeof(buf)); | |
1526 res = Jlookup_by_regs(J, gregs, buf, sizeof(buf), &jframe); | |
1527 if (res != PS_OK) | |
1528 return (-1); | |
1529 | |
1530 | |
1531 res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1, | |
1532 jframe.line, NULL); | |
1533 if (res != 0) { | |
1534 update_gregs(gregs, jframe); | |
1535 return (res); | |
1536 } | |
1537 for (i = 1; i < jframe.vf_cnt; i++) { | |
1538 Jget_vframe(J, i, buf, sizeof(buf), &jframe); | |
1539 res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1, | |
1540 jframe.line, NULL); | |
1541 if (res != 0) { | |
1542 update_gregs(gregs, jframe); | |
1543 return (res); | |
1544 } | |
1545 } | |
1546 update_gregs(gregs, jframe); | |
1547 return (0); | |
1548 } |