Thu, 12 Mar 2009 10:37:46 -0700
6791178: Specialize for zero as the compressed oop vm heap base
Summary: Use zero based compressed oops if java heap is below 32gb and unscaled compressed oops if java heap is below 4gb.
Reviewed-by: never, twisti, jcoomes, coleenp
1 /*
2 * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
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 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <gelf.h>
31 #include "libjvm_db.h"
32 #include "JvmOffsets.h"
34 #define LIBJVM_SO "libjvm.so"
36 #if defined(i386) || defined(__i386) || defined(__amd64)
37 #ifdef COMPILER2
38 #define X86_COMPILER2
39 #endif /* COMPILER2 */
40 #endif /* i386 */
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;
52 int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,
53 size_t size, Jframe_t *jframe);
55 int main(int arg) { return arg; }
57 static int debug = 0;
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 }
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 }
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 }
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)
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;
92 /* Prototyping inlined methods */
94 int sprintf(char *s, const char *format, ...);
96 #define SZ16 sizeof(int16_t)
97 #define SZ32 sizeof(int32_t)
99 #define COMP_METHOD_SIGN '*'
101 #define MAX_VFRAMES_CNT 256
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;
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;
118 typedef struct Nmethod_t {
119 struct jvm_agent* J;
120 Jframe_t *jframe;
122 uint64_t nm; /* _nmethod */
123 uint64_t pc;
124 uint64_t pc_desc;
126 int32_t orig_pc_offset; /* _orig_pc_offset */
127 int32_t instrs_beg; /* _instructions_offset */
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 */
133 int32_t oops_len; /* _oops_length */
134 int32_t scopes_pcs_beg; /* _scopes_pcs_offset */
135 int32_t scopes_pcs_end;
137 int vf_cnt;
138 Vframe_t vframes[MAX_VFRAMES_CNT];
139 } Nmethod_t;
141 struct jvm_agent {
142 struct ps_prochandle* P;
144 uint64_t nmethod_vtbl;
145 uint64_t CodeBlob_vtbl;
146 uint64_t BufferBlob_vtbl;
147 uint64_t RuntimeStub_vtbl;
149 uint64_t Use_Compressed_Oops_address;
150 uint64_t Universe_methodKlassObj_address;
151 uint64_t Universe_narrow_oop_base_address;
152 uint64_t Universe_narrow_oop_shift_address;
153 uint64_t CodeCache_heap_address;
155 /* Volatiles */
156 uint8_t Use_Compressed_Oops;
157 uint64_t Universe_methodKlassObj;
158 uint64_t Universe_narrow_oop_base;
159 uint32_t Universe_narrow_oop_shift;
160 uint64_t CodeCache_low;
161 uint64_t CodeCache_high;
162 uint64_t CodeCache_segmap_low;
163 uint64_t CodeCache_segmap_high;
165 int32_t SIZE_CodeCache_log2_segment;
167 uint64_t methodOopPtr;
168 uint64_t bcx;
170 Nmethod_t *N; /*Inlined methods support */
171 Frame_t prev_fr;
172 Frame_t curr_fr;
173 };
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 }
193 static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) {
194 int err = -1;
195 uint32_t ptr32;
196 err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));
197 *ptr = ptr32;
198 return err;
199 }
201 static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) {
202 int err = -1;
203 uint32_t ptr32;
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 }
215 return err;
216 }
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];
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;
233 fail:
234 return err;
235 }
237 static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) {
238 uint64_t ptr;
239 int err;
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);
248 return PS_OK;
250 fail:
251 if (vmp->typeName != NULL) free((void*)vmp->typeName);
252 if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
253 return err;
254 }
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;
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;
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 }
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 }
286 if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
287 J->Universe_narrow_oop_base_address = vmp->address;
288 }
289 if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) {
290 J->Universe_narrow_oop_shift_address = vmp->address;
291 }
292 }
293 CHECK_FAIL(err);
295 base += SIZE_VMStructEntry;
296 if (vmp->typeName != NULL) free((void*)vmp->typeName);
297 if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
298 }
300 return PS_OK;
302 fail:
303 if (vmp->typeName != NULL) free((void*)vmp->typeName);
304 if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
305 return -1;
306 }
308 static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) {
309 psaddr_t sym_addr;
310 int err;
312 err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);
313 if (err != PS_OK) goto fail;
314 *valuep = sym_addr;
315 return PS_OK;
317 fail:
318 return err;
319 }
321 static int read_volatiles(jvm_agent_t* J) {
322 uint64_t ptr;
323 int err;
325 err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
326 if (err == PS_OK) {
327 err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t));
328 CHECK_FAIL(err);
329 } else {
330 J->Use_Compressed_Oops = 0;
331 }
333 err = read_pointer(J, J->Universe_methodKlassObj_address, &J->Universe_methodKlassObj);
334 CHECK_FAIL(err);
336 err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base);
337 CHECK_FAIL(err);
338 err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
339 CHECK_FAIL(err);
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);
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);
358 return PS_OK;
360 fail:
361 return err;
362 }
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 }
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 }
374 static uint64_t block_at(jvm_agent_t* J, int i) {
375 return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment);
376 }
378 static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
379 int err;
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;
405 fail:
406 return -1;
407 }
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 }
420 jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) {
421 jvm_agent_t* J;
422 int err;
424 if (vers != JVM_DB_VERSION) {
425 errno = ENOTSUP;
426 return NULL;
427 }
429 J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1);
431 debug = getenv("LIBJVMDB_DEBUG") != NULL;
432 if (debug) debug = 3;
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 }
441 J->P = P;
443 // Initialize the initial previous frame
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;
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);
459 err = parse_vmstructs(J);
460 CHECK_FAIL(err);
461 err = read_volatiles(J);
462 CHECK_FAIL(err);
464 return J;
466 fail:
467 Jagent_destroy(J);
468 return NULL;
469 }
471 void Jagent_destroy(jvm_agent_t *J) {
472 if (J != NULL) {
473 free(J);
474 }
475 }
477 static int is_methodOop(jvm_agent_t* J, uint64_t methodOopPtr) {
478 uint64_t klass;
479 int err;
480 // If UseCompressedOops, this was a compressed oop.
481 if (J->Use_Compressed_Oops != 0) {
482 uint32_t cklass;
483 err = read_compressed_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata,
484 &cklass);
485 // decode heap oop, same as oop.inline.hpp
486 klass = (uint64_t)((uintptr_t)J->Universe_narrow_oop_base +
487 ((uintptr_t)cklass << J->Universe_narrow_oop_shift));
488 } else {
489 err = read_pointer(J, methodOopPtr + OFFSET_oopDesc_metadata, &klass);
490 }
491 if (err != PS_OK) goto fail;
492 return klass == J->Universe_methodKlassObj;
494 fail:
495 return 0;
496 }
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;
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);
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);
527 err = ps_pread(J->P, nameSymbol + OFFSET_symbolOopDesc_length, &nameSymbolLength, 2);
528 CHECK_FAIL(err);
529 nameString = (char*)calloc(nameSymbolLength + 1, 1);
530 err = ps_pread(J->P, nameSymbol + OFFSET_symbolOopDesc_body, nameString, nameSymbolLength);
531 CHECK_FAIL(err);
533 /* To get signature string */
534 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_signature_index, &signatureIndex, 2);
535 CHECK_FAIL(err);
536 err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_constantPoolOopDesc, &signatureSymbol);
537 CHECK_FAIL(err);
538 err = ps_pread(J->P, signatureSymbol + OFFSET_symbolOopDesc_length, &signatureSymbolLength, 2);
539 CHECK_FAIL(err);
540 signatureString = (char*)calloc(signatureSymbolLength + 1, 1);
541 err = ps_pread(J->P, signatureSymbol + OFFSET_symbolOopDesc_body, signatureString, signatureSymbolLength);
542 CHECK_FAIL(err);
544 /* To get klass string */
545 err = read_pointer(J, constantPool + OFFSET_constantPoolOopDesc_pool_holder, &klassPtr);
546 CHECK_FAIL(err);
547 err = read_pointer(J, klassPtr + OFFSET_Klass_name + SIZE_oopDesc, &klassSymbol);
548 CHECK_FAIL(err);
549 err = ps_pread(J->P, klassSymbol + OFFSET_symbolOopDesc_length, &klassSymbolLength, 2);
550 CHECK_FAIL(err);
551 klassString = (char*)calloc(klassSymbolLength + 1, 1);
552 err = ps_pread(J->P, klassSymbol + OFFSET_symbolOopDesc_body, klassString, klassSymbolLength);
553 CHECK_FAIL(err);
555 result[0] = '\0';
556 strncat(result, klassString, size);
557 size -= strlen(klassString);
558 strncat(result, ".", size);
559 size -= 1;
560 strncat(result, nameString, size);
561 size -= strlen(nameString);
562 strncat(result, signatureString, size);
564 if (nameString != NULL) free(nameString);
565 if (klassString != NULL) free(klassString);
566 if (signatureString != NULL) free(signatureString);
568 return PS_OK;
570 fail:
571 if (debug) {
572 fprintf(stderr, "name_for_methodOop: FAIL \n\n");
573 }
574 if (nameString != NULL) free(nameString);
575 if (klassString != NULL) free(klassString);
576 if (signatureString != NULL) free(signatureString);
577 return -1;
578 }
580 static int nmethod_info(Nmethod_t *N)
581 {
582 jvm_agent_t *J = N->J;
583 uint64_t nm = N->nm;
584 int32_t err;
586 if (debug > 2 )
587 fprintf(stderr, "\t nmethod_info: BEGIN \n");
589 /* Instructions */
590 err = ps_pread(J->P, nm + OFFSET_CodeBlob_instructions_offset, &N->instrs_beg, SZ32);
591 CHECK_FAIL(err);
592 err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32);
593 CHECK_FAIL(err);
594 err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32);
595 CHECK_FAIL(err);
596 err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32);
597 CHECK_FAIL(err);
599 /* Oops */
600 err = ps_pread(J->P, nm + OFFSET_CodeBlob_oops_offset, &N->oops_beg, SZ32);
601 CHECK_FAIL(err);
602 err = ps_pread(J->P, nm + OFFSET_CodeBlob_oops_length, &N->oops_len, SZ32);
603 CHECK_FAIL(err);
605 /* scopes_pcs */
606 err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32);
607 CHECK_FAIL(err);
608 err = ps_pread(J->P, nm + OFFSET_nmethod_handler_table_offset, &N->scopes_pcs_end, SZ32);
609 CHECK_FAIL(err);
611 /* scopes_data */
612 err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32);
613 CHECK_FAIL(err);
615 if (debug > 2 ) {
616 N->scopes_data_end = N->scopes_pcs_beg;
618 fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n",
619 N->instrs_beg, N->instrs_end);
621 fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n",
622 N->deopt_beg);
624 fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n",
625 N->orig_pc_offset);
627 fprintf(stderr, "\t nmethod_info: oops_beg: %#x, oops_len: %#x\n",
628 N->oops_beg, N->oops_len);
630 fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n",
631 N->scopes_data_beg, N->scopes_data_end);
633 fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n",
634 N->scopes_pcs_beg, N->scopes_pcs_end);
636 fprintf(stderr, "\t nmethod_info: END \n\n");
637 }
638 return PS_OK;
640 fail:
641 return err;
642 }
644 static int
645 raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val)
646 {
647 int shift = 0;
648 int value = 0;
649 uint8_t ch = 0;
650 int32_t err;
651 int32_t sum;
652 // Constants for UNSIGNED5 coding of Pack200
653 // see compressedStream.hpp
654 enum {
655 lg_H = 6,
656 H = 1<<lg_H,
657 BitsPerByte = 8,
658 L = (1<<BitsPerByte)-H,
659 };
660 int i;
662 err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t));
663 CHECK_FAIL(err);
664 if (debug > 2)
665 fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch);
667 sum = ch;
668 if ( sum >= L ) {
669 int32_t lg_H_i = lg_H;
670 // Read maximum of 5 total bytes (we've already read 1).
671 // See CompressedReadStream::read_int_mb
672 for ( i = 0; i < 4; i++) {
673 err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t));
674 CHECK_FAIL(err);
675 sum += ch << lg_H_i;
676 if (ch < L ) {
677 *val = sum;
678 return PS_OK;
679 }
680 lg_H_i += lg_H;
681 }
682 }
683 *val = sum;
684 return PS_OK;
686 fail:
687 return err;
688 }
690 static int
691 read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line)
692 {
693 uint8_t next = 0;
694 int32_t bci_delta;
695 int32_t line_delta;
696 int32_t err;
698 if (debug > 2)
699 fprintf(stderr, "\t\t read_pair: BEGIN\n");
701 err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t));
702 CHECK_FAIL(err);
704 if (next == 0) {
705 if (debug > 2)
706 fprintf(stderr, "\t\t read_pair: END: next == 0\n");
707 return 1; /* stream terminated */
708 }
709 if (next == 0xFF) {
710 if (debug > 2)
711 fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n");
713 /* Escape character, regular compression used */
715 err = raw_read_int(J, buffer, &bci_delta);
716 CHECK_FAIL(err);
718 err = raw_read_int(J, buffer, &line_delta);
719 CHECK_FAIL(err);
721 *bci += bci_delta;
722 *line += line_delta;
724 if (debug > 2) {
725 fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n",
726 line_delta, bci_delta);
727 fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n",
728 *line, *bci);
729 }
730 } else {
731 /* Single byte compression used */
732 *bci += next >> 3;
733 *line += next & 0x7;
734 if (debug > 2) {
735 fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n",
736 next & 0x7, next >> 3);
737 fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n",
738 *line, *bci);
739 }
740 }
741 if (debug > 2)
742 fprintf(stderr, "\t\t read_pair: END\n");
743 return PS_OK;
745 fail:
746 if (debug)
747 fprintf(stderr, "\t\t read_pair: FAIL\n");
748 return err;
749 }
751 static int
752 line_number_from_bci(jvm_agent_t* J, Vframe_t *vf)
753 {
754 uint64_t buffer;
755 uint16_t code_size;
756 uint64_t code_end_delta;
757 uint64_t constMethod;
758 int8_t access_flags;
759 int32_t best_bci = 0;
760 int32_t stream_bci = 0;
761 int32_t stream_line = 0;
762 int32_t err;
764 if (debug > 2) {
765 char name[256];
766 err = name_for_methodOop(J, vf->methodOop, name, 256);
767 CHECK_FAIL(err);
768 fprintf(stderr, "\t line_number_from_bci: BEGIN, method name: %s, targ bci: %d\n",
769 name, vf->bci);
770 }
772 err = read_pointer(J, vf->methodOop + OFFSET_methodOopDesc_constMethod, &constMethod);
773 CHECK_FAIL(err);
775 vf->line = 0;
776 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_flags, &access_flags, sizeof(int8_t));
777 CHECK_FAIL(err);
779 if (!(access_flags & constMethodOopDesc_has_linenumber_table)) {
780 if (debug > 2)
781 fprintf(stderr, "\t line_number_from_bci: END: !HAS_LINE_NUMBER_TABLE \n\n");
782 return PS_OK;
783 }
785 /* The line numbers are a short array of 2-tuples [start_pc, line_number].
786 * Not necessarily sorted and not necessarily one-to-one.
787 */
789 err = ps_pread(J->P, constMethod + OFFSET_constMethodOopDesc_code_size, &code_size, SZ16);
790 CHECK_FAIL(err);
792 /* inlined_table_start() */
793 code_end_delta = (uint64_t) (access_flags & AccessFlags_NATIVE) ? 2*POINTER_SIZE : 0;
794 buffer = constMethod + (uint64_t) SIZE_constMethodOopDesc + (uint64_t) code_size + code_end_delta;
796 if (debug > 2) {
797 fprintf(stderr, "\t\t line_number_from_bci: methodOop: %#llx, native: %d\n",
798 vf->methodOop, (access_flags & AccessFlags_NATIVE));
799 fprintf(stderr, "\t\t line_number_from_bci: buffer: %#llx, code_size: %d\n",
800 buffer, (int) code_size);
801 }
803 while (read_pair(J, &buffer, &stream_bci, &stream_line) == 0) {
804 if (stream_bci == vf->bci) {
805 /* perfect match */
806 if (debug > 2)
807 fprintf(stderr, "\t line_number_from_bci: END: exact line: %ld \n\n", vf->line);
808 vf->line = stream_line;
809 return PS_OK;
810 } else {
811 /* update best_bci/line */
812 if (stream_bci < vf->bci && stream_bci >= best_bci) {
813 best_bci = stream_bci;
814 vf->line = stream_line;
815 if (debug > 2) {
816 fprintf(stderr, "\t line_number_from_bci: best_bci: %ld, best_line: %ld\n",
817 best_bci, vf->line);
818 }
819 }
820 }
821 }
822 if (debug > 2)
823 fprintf(stderr, "\t line_number_from_bci: END: line: %ld \n\n", vf->line);
824 return PS_OK;
826 fail:
827 if (debug)
828 fprintf(stderr, "\t line_number_from_bci: FAIL\n");
829 return err;
830 }
832 static int
833 get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc)
834 {
835 int32_t pc_offset;
836 int32_t err;
838 err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32);
839 CHECK_FAIL(err);
841 *real_pc = N->nm + N->instrs_beg + pc_offset;
842 if (debug > 2) {
843 fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n",
844 pc_offset, *real_pc);
845 }
846 return PS_OK;
848 fail:
849 return err;
850 }
852 /* Finds a PcDesc with real-pc equal to N->pc */
853 static int pc_desc_at(Nmethod_t *N)
854 {
855 uint64_t pc_diff;
856 int32_t offs;
857 int32_t err;
859 if (debug > 2)
860 fprintf(stderr, "\t pc_desc_at: BEGIN\n");
862 N->vf_cnt = 0;
863 N->pc_desc = 0;
865 for (offs = N->scopes_pcs_beg; offs < N->scopes_pcs_end; offs += SIZE_PcDesc) {
866 uint64_t pd;
867 uint64_t best_pc_diff = 16; /* some approximation */
868 uint64_t real_pc = 0;
870 pd = N->nm + offs;
871 err = get_real_pc(N, pd, &real_pc);
872 CHECK_FAIL(err);
874 pc_diff = real_pc - N->pc;
876 /* In general, this fragment should work */
877 if (pc_diff == 0) {
878 N->pc_desc = pd;
879 if (debug) {
880 fprintf(stderr, "\t pc_desc_at: END: pc_desc: FOUND: %#lx \n\n", pd);
881 }
882 return PS_OK;
883 }
884 /* This fragment is to be able to find out an appropriate
885 * pc_desc entry even if pc_desc info is inaccurate.
886 */
887 if (best_pc_diff > pc_diff && pc_diff > 0) {
888 best_pc_diff = pc_diff;
889 N->pc_desc = pd;
890 }
891 }
892 if (debug) {
893 fprintf(stderr, "\t pc_desc_at: END: pc_desc NOT FOUND");
894 if (pc_diff < 20)
895 fprintf(stderr, ", best pc_diff: %d\n\n", pc_diff);
896 else
897 fprintf(stderr, "\n\n");
898 }
899 return PS_OK;
901 fail:
902 return err;
903 }
905 static int
906 scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf)
907 {
908 uint64_t buffer;
909 int32_t err;
911 if (debug > 2) {
912 fprintf(stderr, "\t\t scope_desc_at: BEGIN \n");
913 }
915 buffer = N->nm + N->scopes_data_beg + decode_offset;
917 err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset);
918 CHECK_FAIL(err);
920 err = raw_read_int(N->J, &buffer, &vf->methodIdx);
921 CHECK_FAIL(err);
923 err = raw_read_int(N->J, &buffer, &vf->bci);
924 CHECK_FAIL(err);
926 if (debug > 2) {
927 fprintf(stderr, "\t\t scope_desc_at: sender_decode_offset: %#x\n",
928 vf->sender_decode_offset);
929 fprintf(stderr, "\t\t scope_desc_at: methodIdx: %d\n", vf->methodIdx);
930 fprintf(stderr, "\t\t scope_desc_at: bci: %d\n", vf->bci);
932 fprintf(stderr, "\t\t scope_desc_at: END \n\n");
933 }
934 return PS_OK;
936 fail:
937 return err;
938 }
940 static int
941 scopeDesc_chain(Nmethod_t *N)
942 {
943 int32_t decode_offset = 0;
944 int32_t err;
946 if (debug > 2)
947 fprintf(stderr, "\t scopeDesc_chain: BEGIN\n");
949 err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset,
950 &decode_offset, SZ32);
951 CHECK_FAIL(err);
953 while (decode_offset > 0) {
954 if (debug > 2)
955 fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset);
957 Vframe_t *vf = &N->vframes[N->vf_cnt];
959 err = scope_desc_at(N, decode_offset, vf);
960 CHECK_FAIL(err);
962 if (vf->methodIdx > N->oops_len) {
963 fprintf(stderr, "\t scopeDesc_chain: (methodIdx > oops_len) !\n");
964 return -1;
965 }
966 err = read_pointer(N->J, N->nm + N->oops_beg + (vf->methodIdx-1)*POINTER_SIZE,
967 &vf->methodOop);
968 CHECK_FAIL(err);
970 if (vf->methodOop) {
971 N->vf_cnt++;
972 err = line_number_from_bci(N->J, vf);
973 CHECK_FAIL(err);
974 if (debug > 2) {
975 fprintf(stderr, "\t scopeDesc_chain: methodOop: %#8llx, line: %ld\n",
976 vf->methodOop, vf->line);
977 }
978 }
979 decode_offset = vf->sender_decode_offset;
980 }
981 if (debug > 2)
982 fprintf(stderr, "\t scopeDesc_chain: END \n\n");
983 return PS_OK;
985 fail:
986 if (debug)
987 fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n");
988 return err;
989 }
992 static int
993 name_for_nmethod(jvm_agent_t* J,
994 uint64_t nm,
995 uint64_t pc,
996 uint64_t methodOop,
997 char *result,
998 size_t size,
999 Jframe_t *jframe
1000 ) {
1001 Nmethod_t *N;
1002 Vframe_t *vf;
1003 int32_t err;
1004 int deoptimized = 0;
1006 if (debug) {
1007 fprintf(stderr, "name_for_nmethod: BEGIN: nmethod: %#llx, pc: %#llx\n", nm, pc);
1008 }
1009 if (J->N == NULL) {
1010 J->N = (Nmethod_t *) malloc(sizeof(Nmethod_t));
1011 }
1012 memset(J->N, 0, sizeof(Nmethod_t)); /* Initial stat: all values are zeros */
1013 N = J->N;
1014 N->J = J;
1015 N->nm = nm;
1016 N->pc = pc;
1017 N->jframe = jframe;
1019 err = nmethod_info(N);
1020 CHECK_FAIL(err);
1021 if (debug) {
1022 fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n",
1023 pc, N->nm + N->deopt_beg);
1024 }
1026 /* check for a deoptimized frame */
1027 if ( pc == N->nm + N->deopt_beg) {
1028 uint64_t base;
1029 if (debug) {
1030 fprintf(stderr, "name_for_nmethod: found deoptimized frame\n");
1031 }
1032 if (J->prev_fr.sender_sp != 0) {
1033 base = J->prev_fr.sender_sp + N->orig_pc_offset;
1034 } else {
1035 base = J->curr_fr.sp + N->orig_pc_offset;
1036 }
1037 err = read_pointer(J, base, &N->pc);
1038 CHECK_FAIL(err);
1039 if (debug) {
1040 fprintf(stderr, "name_for_nmethod: found deoptimized frame converting pc from %#8llx to %#8llx\n",
1041 pc, N->pc);
1042 }
1043 deoptimized = 1;
1044 }
1046 err = pc_desc_at(N);
1047 CHECK_FAIL(err);
1049 if (N->pc_desc > 0) {
1050 jframe->locinf = 1;
1051 err = scopeDesc_chain(N);
1052 CHECK_FAIL(err);
1053 }
1054 result[0] = COMP_METHOD_SIGN;
1055 vf = &N->vframes[0];
1056 if (N->vf_cnt > 0) {
1057 jframe->vf_cnt = N->vf_cnt;
1058 jframe->bci = vf->bci;
1059 jframe->line = vf->line;
1060 err = name_for_methodOop(J, N->vframes[0].methodOop, result+1, size-1);
1061 CHECK_FAIL(err);
1062 } else {
1063 err = name_for_methodOop(J, methodOop, result+1, size-1);
1064 CHECK_FAIL(err);
1065 }
1066 if (deoptimized) {
1067 strncat(result + 1, " [deoptimized frame]; ", size-1);
1068 } else {
1069 strncat(result + 1, " [compiled] ", size-1);
1070 }
1071 if (debug)
1072 fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n",
1073 result, N->vf_cnt);
1074 return PS_OK;
1076 fail:
1077 if (debug)
1078 fprintf(stderr, "name_for_nmethod: FAIL \n\n");
1079 return err;
1080 }
1082 int is_bci(intptr_t bcx) {
1083 switch (DATA_MODEL) {
1084 case PR_MODEL_LP64:
1085 return ((uintptr_t) bcx) <= ((uintptr_t) MAX_METHOD_CODE_SIZE) ;
1086 case PR_MODEL_ILP32:
1087 default:
1088 return 0 <= bcx && bcx <= MAX_METHOD_CODE_SIZE;
1089 }
1090 }
1092 static int
1093 name_for_imethod(jvm_agent_t* J,
1094 uint64_t bcx,
1095 uint64_t methodOop,
1096 char *result,
1097 size_t size,
1098 Jframe_t *jframe
1099 ) {
1100 uint64_t bci;
1101 uint64_t constMethod;
1102 Vframe_t vframe = {0};
1103 Vframe_t *vf = &vframe;
1104 int32_t err;
1106 err = read_pointer(J, methodOop + OFFSET_methodOopDesc_constMethod, &constMethod);
1107 CHECK_FAIL(err);
1109 bci = is_bci(bcx) ? bcx : bcx - (constMethod + (uint64_t) SIZE_constMethodOopDesc);
1111 if (debug)
1112 fprintf(stderr, "\t name_for_imethod: BEGIN: methodOop: %#llx\n", methodOop);
1114 err = name_for_methodOop(J, methodOop, result, size);
1115 CHECK_FAIL(err);
1116 if (debug)
1117 fprintf(stderr, "\t name_for_imethod: method name: %s\n", result);
1119 if (bci > 0) {
1120 vf->methodOop = methodOop;
1121 vf->bci = bci;
1122 err = line_number_from_bci(J, vf);
1123 CHECK_FAIL(err);
1124 }
1125 jframe->bci = vf->bci;
1126 jframe->line = vf->line;
1127 jframe->locinf = 1;
1129 if (debug) {
1130 fprintf(stderr, "\t name_for_imethod: END: bci: %d, line: %d\n\n",
1131 vf->bci, vf->line);
1132 }
1133 return PS_OK;
1135 fail:
1136 if (debug)
1137 fprintf(stderr, "\t name_for_imethod: FAIL\n");
1138 return err;
1139 }
1141 static int
1142 name_for_codecache(jvm_agent_t* J, uint64_t fp, uint64_t pc, char * result,
1143 size_t size, Jframe_t *jframe, int* is_interpreted)
1144 {
1145 uint64_t start;
1146 uint64_t vtbl;
1147 int32_t err;
1148 *is_interpreted = 0;
1150 result[0] = '\0';
1152 err = find_start(J, pc, &start);
1153 CHECK_FAIL(err);
1155 err = read_pointer(J, start, &vtbl);
1156 CHECK_FAIL(err);
1158 if (vtbl == J->nmethod_vtbl) {
1159 uint64_t methodOop;
1161 err = read_pointer(J, start + OFFSET_nmethod_method, &methodOop);
1162 CHECK_FAIL(err);
1164 if (debug) {
1165 fprintf(stderr, "name_for_codecache: start: %#8llx, pc: %#8llx, methodOop: %#8llx \n",
1166 start, pc, methodOop);
1167 }
1168 err = name_for_nmethod(J, start, pc, methodOop, result, size, jframe);
1169 CHECK_FAIL(err);
1170 } else if (vtbl == J->BufferBlob_vtbl) {
1171 const char * name;
1173 err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name);
1175 /*
1176 * Temporary usage of string "Interpreter".
1177 * We need some other way to distinguish "StubRoutines"
1178 * and regular interpreted frames.
1179 */
1180 if (err == PS_OK && strncmp(name, "Interpreter", 11) == 0) {
1181 *is_interpreted = 1;
1182 if (is_methodOop(J, J->methodOopPtr)) {
1183 return name_for_imethod(J, J->bcx, J->methodOopPtr, result, size, jframe);
1184 }
1185 }
1187 if (err == PS_OK) {
1188 strncpy(result, name, size);
1189 free((void*)name);
1190 } else {
1191 strncpy(result, "<unknown BufferBlob>", size);
1192 }
1193 /* return PS_OK; */
1194 } else {
1195 const char * name;
1197 err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name);
1198 if (err == PS_OK) {
1199 strncpy(result, name, size);
1200 free((void*)name);
1201 } else {
1202 strncpy(result, "<unknown CodeBlob>", size);
1203 WARN1("unknown CodeBlob: vtbl = 0x%x", vtbl);
1204 }
1205 }
1206 result[size-1] = '\0';
1208 #ifdef X86_COMPILER2
1209 if (vtbl != J->RuntimeStub_vtbl) {
1210 uint64_t trial_pc;
1211 int frame_size;
1212 err = ps_pread(J->P, start + OFFSET_CodeBlob_frame_size,
1213 &frame_size, SZ32);
1214 CHECK_FAIL(err);
1216 // frame_size is in words, we want bytes.
1217 frame_size *= POINTER_SIZE; /* word => byte conversion */
1219 /*
1220 Because c2 doesn't use FP as a framepointer the value of sp/fp we receive
1221 in the initial entry to a set of stack frames containing server frames
1222 will pretty much be nonsense. We can detect that nonsense by looking to
1223 see if the PC we received is correct if we look at the expected storage
1224 location in relation to the FP (ie. POINTER_SIZE(FP) )
1225 */
1227 err = read_pointer(J, fp + POINTER_SIZE , &trial_pc);
1228 if ( (err != PS_OK || trial_pc != pc) && frame_size > 0 ) {
1229 // Either we couldn't even read at the "fp" or the pc didn't match
1230 // both are sure clues that the fp is bogus. We no search the stack
1231 // for a reasonable number of words trying to find the bogus fp
1232 // and the current pc in adjacent words. The we will be able to
1233 // deduce an approximation of the frame pointer and actually get
1234 // the correct stack pointer. Which we can then unwind for the
1235 // next frame.
1236 int i;
1237 uint64_t check;
1238 uint64_t base = J->curr_fr.sp;
1239 uint64_t prev_fp = 0;
1240 for ( i = 0; i < frame_size * 5 ; i++, base += POINTER_SIZE ) {
1241 err = read_pointer(J, base , &check);
1242 CHECK_FAIL(err);
1243 if (check == fp) {
1244 base += POINTER_SIZE;
1245 err = read_pointer(J, base , &check);
1246 CHECK_FAIL(err);
1247 if (check == pc) {
1248 if (debug) {
1249 fprintf(stderr, "name_for_codecache: found matching fp/pc combo at 0x%llx\n", base - POINTER_SIZE);
1250 }
1251 prev_fp = base - 2 * POINTER_SIZE;
1252 break;
1253 }
1254 }
1255 }
1256 if ( prev_fp != 0 ) {
1257 // real_sp is the sp we should have received for this frame
1258 uint64_t real_sp = prev_fp + 2 * POINTER_SIZE;
1259 // +POINTER_SIZE because callee owns the return address so caller's sp is +1 word
1260 jframe->new_sp = real_sp + frame_size + POINTER_SIZE;
1261 err = read_pointer(J, jframe->new_sp - POINTER_SIZE , &jframe->new_pc);
1262 CHECK_FAIL(err);
1263 err = read_pointer(J, jframe->new_sp - 2*POINTER_SIZE, &jframe->new_fp);
1264 CHECK_FAIL(err);
1265 return PS_OK;
1266 }
1267 }
1269 /* A prototype to workaround FP absence */
1270 /*
1271 * frame_size can be 0 for StubRoutines (1) frame.
1272 * In this case it should work with fp as usual.
1273 */
1274 if (frame_size > 0) {
1275 jframe->new_fp = J->prev_fr.fp + frame_size;
1276 jframe->new_sp = jframe->new_fp + 2 * POINTER_SIZE;
1277 } else {
1278 memset(&J->curr_fr, 0, sizeof(Frame_t));
1279 err = read_pointer(J, fp, &jframe->new_fp);
1280 CHECK_FAIL(err);
1282 err = read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc);
1283 CHECK_FAIL(err);
1284 }
1285 if (debug) {
1286 fprintf(stderr, "name_for_codecache: %s, frame_size=%#lx\n",
1287 result, frame_size);
1288 fprintf(stderr, "name_for_codecache: prev_fr.fp=%#lx, fp=%#lx\n",
1289 J->prev_fr.fp, jframe->new_fp);
1290 }
1291 }
1292 #endif /* X86_COMPILER2 */
1294 return PS_OK;
1296 fail:
1297 return err;
1298 }
1300 int Jget_vframe(jvm_agent_t* J, int vframe_no,
1301 char *name, size_t size, Jframe_t *jframe)
1302 {
1303 Nmethod_t *N = J->N;
1304 Vframe_t *vf;
1305 int32_t err;
1307 if (vframe_no >= N->vf_cnt) {
1308 (void) sprintf(name, "Wrong inlinedMethod%1d()", vframe_no);
1309 return -1;
1310 }
1311 vf = N->vframes + vframe_no;
1312 name[0] = COMP_METHOD_SIGN;
1313 err = name_for_methodOop(J, vf->methodOop, name + 1, size);
1314 CHECK_FAIL(err);
1316 jframe->bci = vf->bci;
1317 jframe->line = vf->line;
1318 if (debug) {
1319 fprintf(stderr, "\t Jget_vframe: method name: %s, line: %ld\n",
1320 name, vf->line);
1321 }
1322 return PS_OK;
1324 fail:
1325 if (debug) {
1326 fprintf(stderr, "\t Jget_vframe: FAIL\n");
1327 }
1328 return err;
1329 }
1331 #define MAX_SYM_SIZE 256
1333 int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,
1334 size_t size, Jframe_t *jframe) {
1335 uintptr_t fp;
1336 uintptr_t pc;
1337 /* arguments given to read_pointer need to be worst case sized */
1338 uint64_t methodOopPtr = 0;
1339 uint64_t sender_sp;
1340 uint64_t bcx = 0;
1341 int is_interpreted = 0;
1342 int result = PS_OK;
1343 int err = PS_OK;
1345 if (J == NULL) {
1346 return -1;
1347 }
1349 jframe->vf_cnt = 1;
1350 jframe->new_fp = 0;
1351 jframe->new_pc = 0;
1352 jframe->line = 0;
1353 jframe->bci = 0;
1354 jframe->locinf = 0;
1356 read_volatiles(J);
1357 pc = (uintptr_t) regs[R_PC];
1358 J->curr_fr.pc = pc;
1359 J->curr_fr.fp = regs[R_FP];
1360 J->curr_fr.sp = regs[R_SP];
1362 if (debug)
1363 fprintf(stderr, "Jlookup_by_regs: BEGINs: fp=%#lx, pc=%#lx\n", regs[R_FP], pc);
1365 #if defined(sparc) || defined(__sparc)
1366 /* The following workaround is for SPARC. CALL instruction occupates 8 bytes.
1367 * In the pcDesc structure return pc offset is recorded for CALL instructions.
1368 * regs[R_PC] contains a CALL instruction pc offset.
1369 */
1370 pc += 8;
1371 bcx = (uintptr_t) regs[R_L1];
1372 methodOopPtr = (uintptr_t) regs[R_L2];
1373 sender_sp = regs[R_I5];
1374 if (debug > 2) {
1375 fprintf(stderr, "\nregs[R_I1]=%lx, regs[R_I2]=%lx, regs[R_I5]=%lx, regs[R_L1]=%lx, regs[R_L2]=%lx\n",
1376 regs[R_I1], regs[R_I2], regs[R_I5], regs[R_L1], regs[R_L2]);
1377 }
1378 #elif defined(i386) || defined(__i386) || defined(__amd64)
1380 fp = (uintptr_t) regs[R_FP];
1381 if (J->prev_fr.fp == 0) {
1382 #ifdef X86_COMPILER2
1383 /* A workaround for top java frames */
1384 J->prev_fr.fp = (uintptr_t)(regs[R_SP] - 2 * POINTER_SIZE);
1385 #else
1386 J->prev_fr.fp = (uintptr_t)(regs[R_SP] - POINTER_SIZE);
1387 #endif /* COMPILER2 */
1388 }
1389 if (debug > 2) {
1390 printf("Jlookup_by_regs: J->prev_fr.fp = %#lx\n", J->prev_fr.fp);
1391 }
1393 if (read_pointer(J, fp + OFFSET_interpreter_frame_method, &methodOopPtr) != PS_OK) {
1394 methodOopPtr = 0;
1395 }
1396 if (read_pointer(J, fp + OFFSET_interpreter_frame_sender_sp, &sender_sp) != PS_OK) {
1397 sender_sp = 0;
1398 }
1399 if (read_pointer(J, fp + OFFSET_interpreter_frame_bcx_offset, &bcx) != PS_OK) {
1400 bcx = 0;
1401 }
1402 #endif /* i386 */
1404 J->methodOopPtr = methodOopPtr;
1405 J->bcx = bcx;
1407 /* On x86 with C2 JVM: native frame may have wrong regs[R_FP]
1408 * For example: JVM_SuspendThread frame poins to the top interpreted frame.
1409 * If we call is_methodOop(J, methodOopPtr) before codecache_contains(J, pc)
1410 * then we go over and omit both: nmethod and I2CAdapter frames.
1411 * Note, that regs[R_PC] is always correct if frame defined correctly.
1412 * So it is better to call codecache_contains(J, pc) from the beginning.
1413 */
1414 #ifndef X86_COMPILER2
1415 if (is_methodOop(J, J->methodOopPtr)) {
1416 result = name_for_imethod(J, bcx, J->methodOopPtr, name, size, jframe);
1417 /* If the methodOopPtr is a method then this is highly likely to be
1418 an interpreter frame */
1419 if (result >= 0) {
1420 is_interpreted = 1;
1421 }
1422 } else
1423 #endif /* ! X86_COMPILER2 */
1425 if (codecache_contains(J, pc)) {
1426 result = name_for_codecache(J, fp, pc, name, size, jframe, &is_interpreted);
1427 }
1428 #ifdef X86_COMPILER2
1429 else if (is_methodOop(J, J->methodOopPtr)) {
1430 result = name_for_imethod(J, bcx, J->methodOopPtr, name, size, jframe);
1431 /* If the methodOopPtr is a method then this is highly likely to be
1432 an interpreter frame */
1433 if (result >= 0) {
1434 is_interpreted = 1;
1435 }
1436 }
1437 #endif /* X86_COMPILER2 */
1438 else {
1439 if (debug) {
1440 fprintf(stderr, "Jlookup_by_regs: END with -1\n\n");
1441 }
1442 result = -1;
1443 }
1444 if (!is_interpreted) {
1445 sender_sp = 0;
1446 }
1447 J->curr_fr.sender_sp = sender_sp;
1449 #ifdef X86_COMPILER2
1450 if (!J->curr_fr.fp) {
1451 J->curr_fr.fp = (jframe->new_fp) ? jframe->new_fp : (uintptr_t)regs[R_FP];
1452 }
1453 if (!jframe->new_pc && jframe->new_fp) {
1454 // This seems dubious
1455 read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc);
1456 CHECK_FAIL(err);
1457 if (debug > 2) {
1458 printf("Jlookup_by_regs: (update pc) jframe->new_fp: %#llx, jframe->new_pc: %#llx\n",
1459 jframe->new_fp, jframe->new_pc);
1460 }
1461 }
1463 #endif /* X86_COMPILER2 */
1464 J->prev_fr = J->curr_fr;
1466 if (debug)
1467 fprintf(stderr, "Jlookup_by_regs: END\n\n");
1469 return result;
1471 fail:
1472 return err;
1473 }
1475 void update_gregs(prgregset_t gregs, Jframe_t jframe) {
1476 #ifdef X86_COMPILER2
1477 if (debug > 0) {
1478 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]);
1479 }
1480 /*
1481 * A workaround for java C2 frames with unconventional FP.
1482 * may have to modify regset with new values for FP/PC/SP when needed.
1483 */
1484 if (jframe.new_sp) {
1485 *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) jframe.new_sp;
1486 } else {
1487 // *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) gregs[R_FP] + 2 * POINTER_SIZE;
1488 }
1490 if (jframe.new_fp) {
1491 *((uintptr_t *) &gregs[R_FP]) = (uintptr_t) jframe.new_fp;
1492 }
1493 if (jframe.new_pc) {
1494 *((uintptr_t *) &gregs[R_PC]) = (uintptr_t) jframe.new_pc;
1495 }
1496 if (debug > 0) {
1497 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]);
1498 }
1499 #endif /* X86_COMPILER2 */
1500 }
1502 /*
1503 * Iterates over java frames at current location given by 'gregs'.
1504 *
1505 * Returns -1 if no java frames are present or if an error is encountered.
1506 * Returns the result of calling 'func' if the return value is non-zero.
1507 * Returns 0 otherwise.
1508 */
1509 int Jframe_iter(jvm_agent_t *J, prgregset_t gregs, java_stack_f *func, void* cld) {
1510 char buf[MAX_SYM_SIZE + 1];
1511 Jframe_t jframe;
1512 int i = 0, res;
1513 #ifdef X86_COMPILER2
1514 if (debug > 0) {
1515 fprintf(stderr, "Jframe_iter: Entry sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);
1516 }
1517 #endif /* X86_COMPILER2 */
1519 memset(&jframe, 0, sizeof(Jframe_t));
1520 memset(buf, 0, sizeof(buf));
1521 res = Jlookup_by_regs(J, gregs, buf, sizeof(buf), &jframe);
1522 if (res != PS_OK)
1523 return (-1);
1526 res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1,
1527 jframe.line, NULL);
1528 if (res != 0) {
1529 update_gregs(gregs, jframe);
1530 return (res);
1531 }
1532 for (i = 1; i < jframe.vf_cnt; i++) {
1533 Jget_vframe(J, i, buf, sizeof(buf), &jframe);
1534 res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1,
1535 jframe.line, NULL);
1536 if (res != 0) {
1537 update_gregs(gregs, jframe);
1538 return (res);
1539 }
1540 }
1541 update_gregs(gregs, jframe);
1542 return (0);
1543 }