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 method; 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 */ 133 int32_t metadata_end; 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 uint64_t Method_vtbl; 149 150 uint64_t Use_Compressed_Oops_address; 151 uint64_t Universe_narrow_oop_base_address; 152 uint64_t Universe_narrow_oop_shift_address; 153 uint64_t CodeCache_heap_address; 154 155 /* Volatiles */ 156 uint8_t Use_Compressed_Oops; 157 uint64_t Universe_narrow_oop_base; 158 uint32_t Universe_narrow_oop_shift; 159 uint64_t CodeCache_low; 160 uint64_t CodeCache_high; 161 uint64_t CodeCache_segmap_low; 162 uint64_t CodeCache_segmap_high; 163 164 int32_t SIZE_CodeCache_log2_segment; 165 166 uint64_t methodPtr; 167 uint64_t bcx; 168 169 Nmethod_t *N; /*Inlined methods support */ 170 Frame_t prev_fr; 171 Frame_t curr_fr; 172 }; 173 174 static int 175 read_string(struct ps_prochandle *P, 176 char *buf, /* caller's buffer */ 177 size_t size, /* upper limit on bytes to read */ 178 uintptr_t addr) /* address in process */ 179 { 180 int err = PS_OK; 181 while (size-- > 1 && err == PS_OK) { 182 err = ps_pread(P, addr, buf, 1); 258 uint64_t gHotSpotVMStructs; 259 psaddr_t sym_addr; 260 uint64_t base; 261 int err; 262 263 err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); 264 CHECK_FAIL(err); 265 err = read_pointer(J, sym_addr, &gHotSpotVMStructs); 266 CHECK_FAIL(err); 267 base = gHotSpotVMStructs; 268 269 err = PS_OK; 270 while (err == PS_OK) { 271 memset(vmp, 0, sizeof(VMStructEntry)); 272 err = parse_vmstruct_entry(J, base, vmp); 273 if (err != PS_OK || vmp->typeName == NULL) { 274 break; 275 } 276 277 if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { 278 if (strcmp("_heap", vmp->fieldName) == 0) { 279 err = read_pointer(J, vmp->address, &J->CodeCache_heap_address); 280 } 281 } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { 282 if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { 283 J->Universe_narrow_oop_base_address = vmp->address; 284 } 285 if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { 286 J->Universe_narrow_oop_shift_address = vmp->address; 287 } 288 } 289 CHECK_FAIL(err); 290 291 base += SIZE_VMStructEntry; 292 if (vmp->typeName != NULL) free((void*)vmp->typeName); 293 if (vmp->fieldName != NULL) free((void*)vmp->fieldName); 294 } 295 296 return PS_OK; 297 298 fail: 299 if (vmp->typeName != NULL) free((void*)vmp->typeName); 314 return err; 315 } 316 317 static int read_volatiles(jvm_agent_t* J) { 318 uint64_t ptr; 319 int err; 320 321 err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); 322 if (err == PS_OK) { 323 err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); 324 CHECK_FAIL(err); 325 } else { 326 J->Use_Compressed_Oops = 0; 327 } 328 329 err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); 330 CHECK_FAIL(err); 331 err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); 332 CHECK_FAIL(err); 333 334 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + 335 OFFSET_VirtualSpace_low, &J->CodeCache_low); 336 CHECK_FAIL(err); 337 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + 338 OFFSET_VirtualSpace_high, &J->CodeCache_high); 339 CHECK_FAIL(err); 340 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + 341 OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low); 342 CHECK_FAIL(err); 343 err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + 344 OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high); 345 CHECK_FAIL(err); 346 347 err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size, 348 &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); 349 CHECK_FAIL(err); 350 351 return PS_OK; 352 353 fail: 354 return err; 355 } 356 357 358 static int codecache_contains(jvm_agent_t* J, uint64_t ptr) { 359 /* make sure the code cache is up to date */ 360 return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high); 361 } 362 363 static uint64_t segment_for(jvm_agent_t* J, uint64_t p) { 364 return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment; 365 } 366 367 static uint64_t block_at(jvm_agent_t* J, int i) { 368 return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment); 369 } 370 371 static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { 372 int err; 373 374 *startp = 0; 375 if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) { 376 int32_t used; 377 uint64_t segment = segment_for(J, ptr); 378 uint64_t block = J->CodeCache_segmap_low; 379 uint8_t tag; 380 err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); 381 CHECK_FAIL(err); 382 if (tag == 0xff) 383 return PS_OK; 384 while (tag > 0) { 385 err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); 386 CHECK_FAIL(err); 387 segment -= tag; 388 } 389 block = block_at(J, segment); 390 err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); 391 CHECK_FAIL(err); 392 if (used) { 393 *startp = block + SIZE_HeapBlockHeader; 394 } 395 } 396 return PS_OK; 397 398 fail: 399 return -1; 400 } 401 402 static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { 403 psaddr_t sym_addr; 404 int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); 405 if (err == PS_OK) { 406 err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); 407 return err; 408 } 409 *valuep = -1; 410 return -1; 411 } 412 413 jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) { 414 jvm_agent_t* J; 415 int err; 416 | 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 // Number of code heaps in the code cache 104 #define HEAP_CNT 3 105 106 typedef struct vframe { 107 uint64_t method; 108 int32_t sender_decode_offset; 109 int32_t methodIdx; 110 int32_t bci; 111 int32_t line; 112 } Vframe_t; 113 114 typedef struct frame { 115 uintptr_t fp; 116 uintptr_t pc; 117 uintptr_t sp; 118 uintptr_t sender_sp; // The unextended sp of the caller 119 } Frame_t; 120 121 typedef struct Nmethod_t { 122 struct jvm_agent* J; 123 Jframe_t *jframe; 124 125 uint64_t nm; /* _nmethod */ 136 int32_t metadata_end; 137 int32_t scopes_pcs_beg; /* _scopes_pcs_offset */ 138 int32_t scopes_pcs_end; 139 140 int vf_cnt; 141 Vframe_t vframes[MAX_VFRAMES_CNT]; 142 } Nmethod_t; 143 144 struct jvm_agent { 145 struct ps_prochandle* P; 146 147 uint64_t nmethod_vtbl; 148 uint64_t CodeBlob_vtbl; 149 uint64_t BufferBlob_vtbl; 150 uint64_t RuntimeStub_vtbl; 151 uint64_t Method_vtbl; 152 153 uint64_t Use_Compressed_Oops_address; 154 uint64_t Universe_narrow_oop_base_address; 155 uint64_t Universe_narrow_oop_shift_address; 156 uint64_t CodeCache_heap_address[HEAP_CNT]; 157 158 /* Volatiles */ 159 uint8_t Use_Compressed_Oops; 160 uint64_t Universe_narrow_oop_base; 161 uint32_t Universe_narrow_oop_shift; 162 // Code cache heaps 163 uint64_t Heap_low[HEAP_CNT]; 164 uint64_t Heap_high[HEAP_CNT]; 165 uint64_t Heap_segmap_low[HEAP_CNT]; 166 uint64_t Heap_segmap_high[HEAP_CNT]; 167 168 int32_t SIZE_CodeCache_log2_segment; 169 170 uint64_t methodPtr; 171 uint64_t bcx; 172 173 Nmethod_t *N; /*Inlined methods support */ 174 Frame_t prev_fr; 175 Frame_t curr_fr; 176 }; 177 178 static int 179 read_string(struct ps_prochandle *P, 180 char *buf, /* caller's buffer */ 181 size_t size, /* upper limit on bytes to read */ 182 uintptr_t addr) /* address in process */ 183 { 184 int err = PS_OK; 185 while (size-- > 1 && err == PS_OK) { 186 err = ps_pread(P, addr, buf, 1); 262 uint64_t gHotSpotVMStructs; 263 psaddr_t sym_addr; 264 uint64_t base; 265 int err; 266 267 err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); 268 CHECK_FAIL(err); 269 err = read_pointer(J, sym_addr, &gHotSpotVMStructs); 270 CHECK_FAIL(err); 271 base = gHotSpotVMStructs; 272 273 err = PS_OK; 274 while (err == PS_OK) { 275 memset(vmp, 0, sizeof(VMStructEntry)); 276 err = parse_vmstruct_entry(J, base, vmp); 277 if (err != PS_OK || vmp->typeName == NULL) { 278 break; 279 } 280 281 if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { 282 // Read addresses of code cache heaps 283 if (strcmp("_heap_non_method", vmp->fieldName) == 0) { 284 err = read_pointer(J, vmp->address, &J->CodeCache_heap_address[0]); 285 } else if (strcmp("_heap_non_profiled", vmp->fieldName) == 0) { 286 err = read_pointer(J, vmp->address, &J->CodeCache_heap_address[1]); 287 } else if (strcmp("_heap_profiled", vmp->fieldName) == 0) { 288 err = read_pointer(J, vmp->address, &J->CodeCache_heap_address[2]); 289 } 290 } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { 291 if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { 292 J->Universe_narrow_oop_base_address = vmp->address; 293 } 294 if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { 295 J->Universe_narrow_oop_shift_address = vmp->address; 296 } 297 } 298 CHECK_FAIL(err); 299 300 base += SIZE_VMStructEntry; 301 if (vmp->typeName != NULL) free((void*)vmp->typeName); 302 if (vmp->fieldName != NULL) free((void*)vmp->fieldName); 303 } 304 305 return PS_OK; 306 307 fail: 308 if (vmp->typeName != NULL) free((void*)vmp->typeName); 323 return err; 324 } 325 326 static int read_volatiles(jvm_agent_t* J) { 327 uint64_t ptr; 328 int err; 329 330 err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); 331 if (err == PS_OK) { 332 err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); 333 CHECK_FAIL(err); 334 } else { 335 J->Use_Compressed_Oops = 0; 336 } 337 338 err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); 339 CHECK_FAIL(err); 340 err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); 341 CHECK_FAIL(err); 342 343 /* Read code heap information */ 344 int i; 345 for (i = 0; i < HEAP_CNT; ++i) { 346 err = read_pointer(J, J->CodeCache_heap_address[i] + OFFSET_CodeHeap_memory + 347 OFFSET_VirtualSpace_low, &J->Heap_low[i]); 348 CHECK_FAIL(err); 349 err = read_pointer(J, J->CodeCache_heap_address[i] + OFFSET_CodeHeap_memory + 350 OFFSET_VirtualSpace_high, &J->Heap_low[i]); 351 CHECK_FAIL(err); 352 err = read_pointer(J, J->CodeCache_heap_address[i] + OFFSET_CodeHeap_segmap + 353 OFFSET_VirtualSpace_low, &J->Heap_segmap_low[i]); 354 CHECK_FAIL(err); 355 err = read_pointer(J, J->CodeCache_heap_address[i] + OFFSET_CodeHeap_segmap + 356 OFFSET_VirtualSpace_high, &J->Heap_segmap_high[i]); 357 CHECK_FAIL(err); 358 } 359 360 err = ps_pread(J->P, J->CodeCache_heap_address[0] + OFFSET_CodeHeap_log2_segment_size, 361 &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); 362 CHECK_FAIL(err); 363 364 return PS_OK; 365 366 fail: 367 return err; 368 } 369 370 static int codeheap_contains(int heap_num, jvm_agent_t* J, uint64_t ptr) { 371 return (J->Heap_low[heap_num] <= ptr && ptr < J->Heap_high[heap_num]); 372 } 373 374 static int codecache_contains(jvm_agent_t* J, uint64_t ptr) { 375 int i; 376 for (i = 0; i < HEAP_CNT; ++i) { 377 if (codeheap_contains(i, J, ptr)) { 378 return 1; 379 } 380 } 381 return 0; 382 } 383 384 static uint64_t segment_for(int heap_num, jvm_agent_t* J, uint64_t p) { 385 return (p - J->Heap_low[heap_num]) >> J->SIZE_CodeCache_log2_segment; 386 } 387 388 static uint64_t block_at(int heap_num, jvm_agent_t* J, int i) { 389 return J->Heap_low[heap_num] + (i << J->SIZE_CodeCache_log2_segment); 390 } 391 392 static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { 393 int err; 394 395 for (int i = 0; i < HEAP_CNT; ++i) { 396 *startp = 0; 397 if (codeheap_contains(i, J, ptr)) { 398 int32_t used; 399 uint64_t segment = segment_for(i, J, ptr); 400 uint64_t block = J->Heap_segmap_low[i]; 401 uint8_t tag; 402 err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); 403 CHECK_FAIL(err); 404 if (tag == 0xff) 405 return PS_OK; 406 while (tag > 0) { 407 err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); 408 CHECK_FAIL(err); 409 segment -= tag; 410 } 411 block = block_at(i, J, segment); 412 err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); 413 CHECK_FAIL(err); 414 if (used) { 415 *startp = block + SIZE_HeapBlockHeader; 416 } 417 } 418 return PS_OK; 419 } 420 421 fail: 422 return -1; 423 } 424 425 static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { 426 psaddr_t sym_addr; 427 int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); 428 if (err == PS_OK) { 429 err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); 430 return err; 431 } 432 *valuep = -1; 433 return -1; 434 } 435 436 jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) { 437 jvm_agent_t* J; 438 int err; 439 |