1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/os/solaris/dtrace/libjvm_db.c Wed Apr 27 01:25:04 2016 +0800 1.3 @@ -0,0 +1,1532 @@ 1.4 +/* 1.5 + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include <stdio.h> 1.29 +#include <stdlib.h> 1.30 +#include <string.h> 1.31 +#include <errno.h> 1.32 +#include <gelf.h> 1.33 + 1.34 +#include "libjvm_db.h" 1.35 +#include "JvmOffsets.h" 1.36 + 1.37 +#define LIBJVM_SO "libjvm.so" 1.38 + 1.39 +#if defined(i386) || defined(__i386) || defined(__amd64) 1.40 +#ifdef COMPILER2 1.41 +#define X86_COMPILER2 1.42 +#endif /* COMPILER2 */ 1.43 +#endif /* i386 */ 1.44 + 1.45 +typedef struct { 1.46 + short vf_cnt; /* number of recognized java vframes */ 1.47 + short bci; /* current frame method byte code index */ 1.48 + int line; /* current frame method source line */ 1.49 + uint64_t new_fp; /* fp for the next frame */ 1.50 + uint64_t new_pc; /* pc for the next frame */ 1.51 + uint64_t new_sp; /* "raw" sp for the next frame (includes extension by interpreter/adapter */ 1.52 + char locinf; /* indicates there is valid location info */ 1.53 +} Jframe_t; 1.54 + 1.55 +int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name, 1.56 + size_t size, Jframe_t *jframe); 1.57 + 1.58 +int main(int arg) { return arg; } 1.59 + 1.60 +static int debug = 0; 1.61 + 1.62 +static void failed(int err, const char * file, int line) { 1.63 + if (debug) { 1.64 + fprintf(stderr, "failed %d at %s:%d\n", err, file, line); 1.65 + } 1.66 +} 1.67 + 1.68 +static void warn(const char * file, int line, const char * msg) { 1.69 + if (debug) { 1.70 + fprintf(stderr, "warning: %s at %s:%d\n", msg, file, line); 1.71 + } 1.72 +} 1.73 + 1.74 +static void warn1(const char * file, int line, const char * msg, intptr_t arg1) { 1.75 + if (debug) { 1.76 + fprintf(stderr, "warning: "); 1.77 + fprintf(stderr, msg, arg1); 1.78 + fprintf(stderr, " at %s:%d\n", file, line); 1.79 + } 1.80 +} 1.81 + 1.82 +#define CHECK_FAIL(err) \ 1.83 + if (err != PS_OK) { failed(err, __FILE__, __LINE__); goto fail; } 1.84 +#define WARN(msg) warn(__FILE__, __LINE__, msg) 1.85 +#define WARN1(msg, arg1) warn1(__FILE__, __LINE__, msg, arg1) 1.86 + 1.87 +typedef struct VMStructEntry { 1.88 + const char * typeName; /* The type name containing the given field (example: "Klass") */ 1.89 + const char * fieldName; /* The field name within the type (example: "_name") */ 1.90 + uint64_t address; /* Address of field; only used for static fields */ 1.91 + /* ("offset" can not be reused because of apparent SparcWorks compiler bug */ 1.92 + /* in generation of initializer data) */ 1.93 +} VMStructEntry; 1.94 + 1.95 +/* Prototyping inlined methods */ 1.96 + 1.97 +int sprintf(char *s, const char *format, ...); 1.98 + 1.99 +#define SZ16 sizeof(int16_t) 1.100 +#define SZ32 sizeof(int32_t) 1.101 + 1.102 +#define COMP_METHOD_SIGN '*' 1.103 + 1.104 +#define MAX_VFRAMES_CNT 256 1.105 + 1.106 +typedef struct vframe { 1.107 + uint64_t method; 1.108 + int32_t sender_decode_offset; 1.109 + int32_t methodIdx; 1.110 + int32_t bci; 1.111 + int32_t line; 1.112 +} Vframe_t; 1.113 + 1.114 +typedef struct frame { 1.115 + uintptr_t fp; 1.116 + uintptr_t pc; 1.117 + uintptr_t sp; 1.118 + uintptr_t sender_sp; // The unextended sp of the caller 1.119 +} Frame_t; 1.120 + 1.121 +typedef struct Nmethod_t { 1.122 + struct jvm_agent* J; 1.123 + Jframe_t *jframe; 1.124 + 1.125 + uint64_t nm; /* _nmethod */ 1.126 + uint64_t pc; 1.127 + uint64_t pc_desc; 1.128 + 1.129 + int32_t orig_pc_offset; /* _orig_pc_offset */ 1.130 + int32_t instrs_beg; /* _code_offset */ 1.131 + int32_t instrs_end; 1.132 + int32_t deopt_beg; /* _deoptimize_offset */ 1.133 + int32_t scopes_data_beg; /* _scopes_data_offset */ 1.134 + int32_t scopes_data_end; 1.135 + int32_t metadata_beg; /* _metadata_offset */ 1.136 + int32_t metadata_end; 1.137 + int32_t scopes_pcs_beg; /* _scopes_pcs_offset */ 1.138 + int32_t scopes_pcs_end; 1.139 + 1.140 + int vf_cnt; 1.141 + Vframe_t vframes[MAX_VFRAMES_CNT]; 1.142 +} Nmethod_t; 1.143 + 1.144 +struct jvm_agent { 1.145 + struct ps_prochandle* P; 1.146 + 1.147 + uint64_t nmethod_vtbl; 1.148 + uint64_t CodeBlob_vtbl; 1.149 + uint64_t BufferBlob_vtbl; 1.150 + uint64_t RuntimeStub_vtbl; 1.151 + uint64_t Method_vtbl; 1.152 + 1.153 + uint64_t Use_Compressed_Oops_address; 1.154 + uint64_t Universe_narrow_oop_base_address; 1.155 + uint64_t Universe_narrow_oop_shift_address; 1.156 + uint64_t CodeCache_heap_address; 1.157 + 1.158 + /* Volatiles */ 1.159 + uint8_t Use_Compressed_Oops; 1.160 + uint64_t Universe_narrow_oop_base; 1.161 + uint32_t Universe_narrow_oop_shift; 1.162 + uint64_t CodeCache_low; 1.163 + uint64_t CodeCache_high; 1.164 + uint64_t CodeCache_segmap_low; 1.165 + uint64_t CodeCache_segmap_high; 1.166 + 1.167 + int32_t SIZE_CodeCache_log2_segment; 1.168 + 1.169 + uint64_t methodPtr; 1.170 + uint64_t bcx; 1.171 + 1.172 + Nmethod_t *N; /*Inlined methods support */ 1.173 + Frame_t prev_fr; 1.174 + Frame_t curr_fr; 1.175 +}; 1.176 + 1.177 +static int 1.178 +read_string(struct ps_prochandle *P, 1.179 + char *buf, /* caller's buffer */ 1.180 + size_t size, /* upper limit on bytes to read */ 1.181 + uintptr_t addr) /* address in process */ 1.182 +{ 1.183 + int err = PS_OK; 1.184 + while (size-- > 1 && err == PS_OK) { 1.185 + err = ps_pread(P, addr, buf, 1); 1.186 + if (*buf == '\0') { 1.187 + return PS_OK; 1.188 + } 1.189 + addr += 1; 1.190 + buf += 1; 1.191 + } 1.192 + return -1; 1.193 +} 1.194 + 1.195 +static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) { 1.196 + int err = -1; 1.197 + uint32_t ptr32; 1.198 + err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); 1.199 + *ptr = ptr32; 1.200 + return err; 1.201 +} 1.202 + 1.203 +static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) { 1.204 + int err = -1; 1.205 + uint32_t ptr32; 1.206 + 1.207 + switch (DATA_MODEL) { 1.208 + case PR_MODEL_LP64: 1.209 + err = ps_pread(J->P, base, ptr, sizeof(uint64_t)); 1.210 + break; 1.211 + case PR_MODEL_ILP32: 1.212 + err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); 1.213 + *ptr = ptr32; 1.214 + break; 1.215 + } 1.216 + 1.217 + return err; 1.218 +} 1.219 + 1.220 +static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) { 1.221 + uint64_t ptr; 1.222 + int err; 1.223 + char buffer[1024]; 1.224 + 1.225 + *stringp = NULL; 1.226 + err = read_pointer(J, base, &ptr); 1.227 + CHECK_FAIL(err); 1.228 + if (ptr != 0) { 1.229 + err = read_string(J->P, buffer, sizeof(buffer), ptr); 1.230 + CHECK_FAIL(err); 1.231 + *stringp = strdup(buffer); 1.232 + } 1.233 + return PS_OK; 1.234 + 1.235 + fail: 1.236 + return err; 1.237 +} 1.238 + 1.239 +static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) { 1.240 + uint64_t ptr; 1.241 + int err; 1.242 + 1.243 + err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName); 1.244 + CHECK_FAIL(err); 1.245 + err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName); 1.246 + CHECK_FAIL(err); 1.247 + err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address); 1.248 + CHECK_FAIL(err); 1.249 + 1.250 + return PS_OK; 1.251 + 1.252 + fail: 1.253 + if (vmp->typeName != NULL) free((void*)vmp->typeName); 1.254 + if (vmp->fieldName != NULL) free((void*)vmp->fieldName); 1.255 + return err; 1.256 +} 1.257 + 1.258 +static int parse_vmstructs(jvm_agent_t* J) { 1.259 + VMStructEntry vmVar; 1.260 + VMStructEntry* vmp = &vmVar; 1.261 + uint64_t gHotSpotVMStructs; 1.262 + psaddr_t sym_addr; 1.263 + uint64_t base; 1.264 + int err; 1.265 + 1.266 + err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); 1.267 + CHECK_FAIL(err); 1.268 + err = read_pointer(J, sym_addr, &gHotSpotVMStructs); 1.269 + CHECK_FAIL(err); 1.270 + base = gHotSpotVMStructs; 1.271 + 1.272 + err = PS_OK; 1.273 + while (err == PS_OK) { 1.274 + memset(vmp, 0, sizeof(VMStructEntry)); 1.275 + err = parse_vmstruct_entry(J, base, vmp); 1.276 + if (err != PS_OK || vmp->typeName == NULL) { 1.277 + break; 1.278 + } 1.279 + 1.280 + if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { 1.281 + if (strcmp("_heap", vmp->fieldName) == 0) { 1.282 + err = read_pointer(J, vmp->address, &J->CodeCache_heap_address); 1.283 + } 1.284 + } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { 1.285 + if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { 1.286 + J->Universe_narrow_oop_base_address = vmp->address; 1.287 + } 1.288 + if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { 1.289 + J->Universe_narrow_oop_shift_address = vmp->address; 1.290 + } 1.291 + } 1.292 + CHECK_FAIL(err); 1.293 + 1.294 + base += SIZE_VMStructEntry; 1.295 + if (vmp->typeName != NULL) free((void*)vmp->typeName); 1.296 + if (vmp->fieldName != NULL) free((void*)vmp->fieldName); 1.297 + } 1.298 + 1.299 + return PS_OK; 1.300 + 1.301 + fail: 1.302 + if (vmp->typeName != NULL) free((void*)vmp->typeName); 1.303 + if (vmp->fieldName != NULL) free((void*)vmp->fieldName); 1.304 + return -1; 1.305 +} 1.306 + 1.307 +static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { 1.308 + psaddr_t sym_addr; 1.309 + int err; 1.310 + 1.311 + err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); 1.312 + if (err != PS_OK) goto fail; 1.313 + *valuep = sym_addr; 1.314 + return PS_OK; 1.315 + 1.316 + fail: 1.317 + return err; 1.318 +} 1.319 + 1.320 +static int read_volatiles(jvm_agent_t* J) { 1.321 + uint64_t ptr; 1.322 + int err; 1.323 + 1.324 + err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); 1.325 + if (err == PS_OK) { 1.326 + err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); 1.327 + CHECK_FAIL(err); 1.328 + } else { 1.329 + J->Use_Compressed_Oops = 0; 1.330 + } 1.331 + 1.332 + err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); 1.333 + CHECK_FAIL(err); 1.334 + err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); 1.335 + CHECK_FAIL(err); 1.336 + 1.337 + err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + 1.338 + OFFSET_VirtualSpace_low, &J->CodeCache_low); 1.339 + CHECK_FAIL(err); 1.340 + err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + 1.341 + OFFSET_VirtualSpace_high, &J->CodeCache_high); 1.342 + CHECK_FAIL(err); 1.343 + err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + 1.344 + OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low); 1.345 + CHECK_FAIL(err); 1.346 + err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + 1.347 + OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high); 1.348 + CHECK_FAIL(err); 1.349 + 1.350 + err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size, 1.351 + &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); 1.352 + CHECK_FAIL(err); 1.353 + 1.354 + return PS_OK; 1.355 + 1.356 + fail: 1.357 + return err; 1.358 +} 1.359 + 1.360 + 1.361 +static int codecache_contains(jvm_agent_t* J, uint64_t ptr) { 1.362 + /* make sure the code cache is up to date */ 1.363 + return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high); 1.364 +} 1.365 + 1.366 +static uint64_t segment_for(jvm_agent_t* J, uint64_t p) { 1.367 + return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment; 1.368 +} 1.369 + 1.370 +static uint64_t block_at(jvm_agent_t* J, int i) { 1.371 + return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment); 1.372 +} 1.373 + 1.374 +static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { 1.375 + int err; 1.376 + 1.377 + *startp = 0; 1.378 + if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) { 1.379 + int32_t used; 1.380 + uint64_t segment = segment_for(J, ptr); 1.381 + uint64_t block = J->CodeCache_segmap_low; 1.382 + uint8_t tag; 1.383 + err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); 1.384 + CHECK_FAIL(err); 1.385 + if (tag == 0xff) 1.386 + return PS_OK; 1.387 + while (tag > 0) { 1.388 + err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); 1.389 + CHECK_FAIL(err); 1.390 + segment -= tag; 1.391 + } 1.392 + block = block_at(J, segment); 1.393 + err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); 1.394 + CHECK_FAIL(err); 1.395 + if (used) { 1.396 + *startp = block + SIZE_HeapBlockHeader; 1.397 + } 1.398 + } 1.399 + return PS_OK; 1.400 + 1.401 + fail: 1.402 + return -1; 1.403 +} 1.404 + 1.405 +static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { 1.406 + psaddr_t sym_addr; 1.407 + int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); 1.408 + if (err == PS_OK) { 1.409 + err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); 1.410 + return err; 1.411 + } 1.412 + *valuep = -1; 1.413 + return -1; 1.414 +} 1.415 + 1.416 +jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) { 1.417 + jvm_agent_t* J; 1.418 + int err; 1.419 + 1.420 + if (vers != JVM_DB_VERSION) { 1.421 + errno = ENOTSUP; 1.422 + return NULL; 1.423 + } 1.424 + 1.425 + J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1); 1.426 + 1.427 + debug = getenv("LIBJVMDB_DEBUG") != NULL; 1.428 + if (debug) debug = 3; 1.429 + 1.430 + if (debug) { 1.431 + fprintf(stderr, "Jagent_create: debug=%d\n", debug); 1.432 +#ifdef X86_COMPILER2 1.433 + fprintf(stderr, "Jagent_create: R_SP=%d, R_FP=%d, POINTER_SIZE=%d\n", R_SP, R_FP, POINTER_SIZE); 1.434 +#endif /* X86_COMPILER2 */ 1.435 + } 1.436 + 1.437 + J->P = P; 1.438 + 1.439 + // Initialize the initial previous frame 1.440 + 1.441 + J->prev_fr.fp = 0; 1.442 + J->prev_fr.pc = 0; 1.443 + J->prev_fr.sp = 0; 1.444 + J->prev_fr.sender_sp = 0; 1.445 + 1.446 + err = find_symbol(J, "__1cHnmethodG__vtbl_", &J->nmethod_vtbl); 1.447 + CHECK_FAIL(err); 1.448 + err = find_symbol(J, "__1cKBufferBlobG__vtbl_", &J->BufferBlob_vtbl); 1.449 + if (err != PS_OK) J->BufferBlob_vtbl = 0; 1.450 + err = find_symbol(J, "__1cICodeBlobG__vtbl_", &J->CodeBlob_vtbl); 1.451 + CHECK_FAIL(err); 1.452 + err = find_symbol(J, "__1cLRuntimeStubG__vtbl_", &J->RuntimeStub_vtbl); 1.453 + CHECK_FAIL(err); 1.454 + err = find_symbol(J, "__1cGMethodG__vtbl_", &J->Method_vtbl); 1.455 + CHECK_FAIL(err); 1.456 + 1.457 + err = parse_vmstructs(J); 1.458 + CHECK_FAIL(err); 1.459 + err = read_volatiles(J); 1.460 + CHECK_FAIL(err); 1.461 + 1.462 + return J; 1.463 + 1.464 + fail: 1.465 + Jagent_destroy(J); 1.466 + return NULL; 1.467 +} 1.468 + 1.469 +void Jagent_destroy(jvm_agent_t *J) { 1.470 + if (J != NULL) { 1.471 + free(J); 1.472 + } 1.473 +} 1.474 + 1.475 +static int is_method(jvm_agent_t* J, uint64_t methodPtr) { 1.476 + uint64_t klass; 1.477 + int err = read_pointer(J, methodPtr, &klass); 1.478 + if (err != PS_OK) goto fail; 1.479 + return klass == J->Method_vtbl; 1.480 + 1.481 + fail: 1.482 + return 0; 1.483 +} 1.484 + 1.485 +static int 1.486 +name_for_methodPtr(jvm_agent_t* J, uint64_t methodPtr, char * result, size_t size) 1.487 +{ 1.488 + short nameIndex; 1.489 + short signatureIndex; 1.490 + uint64_t constantPool; 1.491 + uint64_t constMethod; 1.492 + uint64_t nameSymbol; 1.493 + uint64_t signatureSymbol; 1.494 + uint64_t klassPtr; 1.495 + uint64_t klassSymbol; 1.496 + short klassSymbolLength; 1.497 + short nameSymbolLength; 1.498 + short signatureSymbolLength; 1.499 + char * nameString = NULL; 1.500 + char * klassString = NULL; 1.501 + char * signatureString = NULL; 1.502 + int err; 1.503 + 1.504 + err = read_pointer(J, methodPtr + OFFSET_Method_constMethod, &constMethod); 1.505 + CHECK_FAIL(err); 1.506 + err = read_pointer(J, constMethod + OFFSET_ConstMethod_constants, &constantPool); 1.507 + CHECK_FAIL(err); 1.508 + 1.509 + /* To get name string */ 1.510 + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_name_index, &nameIndex, 2); 1.511 + CHECK_FAIL(err); 1.512 + err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_ConstantPool, &nameSymbol); 1.513 + CHECK_FAIL(err); 1.514 + // The symbol is a CPSlot and has lower bit set to indicate metadata 1.515 + nameSymbol &= (~1); // remove metadata lsb 1.516 + err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2); 1.517 + CHECK_FAIL(err); 1.518 + nameString = (char*)calloc(nameSymbolLength + 1, 1); 1.519 + err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength); 1.520 + CHECK_FAIL(err); 1.521 + 1.522 + /* To get signature string */ 1.523 + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_signature_index, &signatureIndex, 2); 1.524 + CHECK_FAIL(err); 1.525 + err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_ConstantPool, &signatureSymbol); 1.526 + CHECK_FAIL(err); 1.527 + signatureSymbol &= (~1); // remove metadata lsb 1.528 + err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2); 1.529 + CHECK_FAIL(err); 1.530 + signatureString = (char*)calloc(signatureSymbolLength + 1, 1); 1.531 + err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength); 1.532 + CHECK_FAIL(err); 1.533 + 1.534 + /* To get klass string */ 1.535 + err = read_pointer(J, constantPool + OFFSET_ConstantPool_pool_holder, &klassPtr); 1.536 + CHECK_FAIL(err); 1.537 + err = read_pointer(J, klassPtr + OFFSET_Klass_name, &klassSymbol); 1.538 + CHECK_FAIL(err); 1.539 + err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2); 1.540 + CHECK_FAIL(err); 1.541 + klassString = (char*)calloc(klassSymbolLength + 1, 1); 1.542 + err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength); 1.543 + CHECK_FAIL(err); 1.544 + 1.545 + result[0] = '\0'; 1.546 + strncat(result, klassString, size); 1.547 + size -= strlen(klassString); 1.548 + strncat(result, ".", size); 1.549 + size -= 1; 1.550 + strncat(result, nameString, size); 1.551 + size -= strlen(nameString); 1.552 + strncat(result, signatureString, size); 1.553 + 1.554 + if (nameString != NULL) free(nameString); 1.555 + if (klassString != NULL) free(klassString); 1.556 + if (signatureString != NULL) free(signatureString); 1.557 + 1.558 + return PS_OK; 1.559 + 1.560 + fail: 1.561 + if (debug) { 1.562 + fprintf(stderr, "name_for_methodPtr: FAIL \n\n"); 1.563 + } 1.564 + if (nameString != NULL) free(nameString); 1.565 + if (klassString != NULL) free(klassString); 1.566 + if (signatureString != NULL) free(signatureString); 1.567 + return -1; 1.568 +} 1.569 + 1.570 +static int nmethod_info(Nmethod_t *N) 1.571 +{ 1.572 + jvm_agent_t *J = N->J; 1.573 + uint64_t nm = N->nm; 1.574 + int32_t err; 1.575 + 1.576 + if (debug > 2 ) 1.577 + fprintf(stderr, "\t nmethod_info: BEGIN \n"); 1.578 + 1.579 + /* Instructions */ 1.580 + err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32); 1.581 + CHECK_FAIL(err); 1.582 + err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32); 1.583 + CHECK_FAIL(err); 1.584 + err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32); 1.585 + CHECK_FAIL(err); 1.586 + err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32); 1.587 + CHECK_FAIL(err); 1.588 + 1.589 + /* Metadata */ 1.590 + err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32); 1.591 + CHECK_FAIL(err); 1.592 + err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->metadata_end, SZ32); 1.593 + CHECK_FAIL(err); 1.594 + 1.595 + /* scopes_pcs */ 1.596 + err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32); 1.597 + CHECK_FAIL(err); 1.598 + err = ps_pread(J->P, nm + OFFSET_nmethod_handler_table_offset, &N->scopes_pcs_end, SZ32); 1.599 + CHECK_FAIL(err); 1.600 + 1.601 + /* scopes_data */ 1.602 + err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32); 1.603 + CHECK_FAIL(err); 1.604 + 1.605 + if (debug > 2 ) { 1.606 + N->scopes_data_end = N->scopes_pcs_beg; 1.607 + 1.608 + fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n", 1.609 + N->instrs_beg, N->instrs_end); 1.610 + 1.611 + fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n", 1.612 + N->deopt_beg); 1.613 + 1.614 + fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n", 1.615 + N->orig_pc_offset); 1.616 + 1.617 + fprintf(stderr, "\t nmethod_info: metadata_beg: %#x, metadata_end: %#x\n", 1.618 + N->metadata_beg, N->metadata_end); 1.619 + 1.620 + fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n", 1.621 + N->scopes_data_beg, N->scopes_data_end); 1.622 + 1.623 + fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n", 1.624 + N->scopes_pcs_beg, N->scopes_pcs_end); 1.625 + 1.626 + fprintf(stderr, "\t nmethod_info: END \n\n"); 1.627 + } 1.628 + return PS_OK; 1.629 + 1.630 + fail: 1.631 + return err; 1.632 +} 1.633 + 1.634 +static int 1.635 +raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val) 1.636 +{ 1.637 + int shift = 0; 1.638 + int value = 0; 1.639 + uint8_t ch = 0; 1.640 + int32_t err; 1.641 + int32_t sum; 1.642 + // Constants for UNSIGNED5 coding of Pack200 1.643 + // see compressedStream.hpp 1.644 + enum { 1.645 + lg_H = 6, 1.646 + H = 1<<lg_H, 1.647 + BitsPerByte = 8, 1.648 + L = (1<<BitsPerByte)-H, 1.649 + }; 1.650 + int i; 1.651 + 1.652 + err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); 1.653 + CHECK_FAIL(err); 1.654 + if (debug > 2) 1.655 + fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch); 1.656 + 1.657 + sum = ch; 1.658 + if ( sum >= L ) { 1.659 + int32_t lg_H_i = lg_H; 1.660 + // Read maximum of 5 total bytes (we've already read 1). 1.661 + // See CompressedReadStream::read_int_mb 1.662 + for ( i = 0; i < 4; i++) { 1.663 + err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); 1.664 + CHECK_FAIL(err); 1.665 + sum += ch << lg_H_i; 1.666 + if (ch < L ) { 1.667 + *val = sum; 1.668 + return PS_OK; 1.669 + } 1.670 + lg_H_i += lg_H; 1.671 + } 1.672 + } 1.673 + *val = sum; 1.674 + return PS_OK; 1.675 + 1.676 + fail: 1.677 + return err; 1.678 +} 1.679 + 1.680 +static int 1.681 +read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line) 1.682 +{ 1.683 + uint8_t next = 0; 1.684 + int32_t bci_delta; 1.685 + int32_t line_delta; 1.686 + int32_t err; 1.687 + 1.688 + if (debug > 2) 1.689 + fprintf(stderr, "\t\t read_pair: BEGIN\n"); 1.690 + 1.691 + err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t)); 1.692 + CHECK_FAIL(err); 1.693 + 1.694 + if (next == 0) { 1.695 + if (debug > 2) 1.696 + fprintf(stderr, "\t\t read_pair: END: next == 0\n"); 1.697 + return 1; /* stream terminated */ 1.698 + } 1.699 + if (next == 0xFF) { 1.700 + if (debug > 2) 1.701 + fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n"); 1.702 + 1.703 + /* Escape character, regular compression used */ 1.704 + 1.705 + err = raw_read_int(J, buffer, &bci_delta); 1.706 + CHECK_FAIL(err); 1.707 + 1.708 + err = raw_read_int(J, buffer, &line_delta); 1.709 + CHECK_FAIL(err); 1.710 + 1.711 + *bci += bci_delta; 1.712 + *line += line_delta; 1.713 + 1.714 + if (debug > 2) { 1.715 + fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", 1.716 + line_delta, bci_delta); 1.717 + fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", 1.718 + *line, *bci); 1.719 + } 1.720 + } else { 1.721 + /* Single byte compression used */ 1.722 + *bci += next >> 3; 1.723 + *line += next & 0x7; 1.724 + if (debug > 2) { 1.725 + fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", 1.726 + next & 0x7, next >> 3); 1.727 + fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", 1.728 + *line, *bci); 1.729 + } 1.730 + } 1.731 + if (debug > 2) 1.732 + fprintf(stderr, "\t\t read_pair: END\n"); 1.733 + return PS_OK; 1.734 + 1.735 + fail: 1.736 + if (debug) 1.737 + fprintf(stderr, "\t\t read_pair: FAIL\n"); 1.738 + return err; 1.739 +} 1.740 + 1.741 +static int 1.742 +line_number_from_bci(jvm_agent_t* J, Vframe_t *vf) 1.743 +{ 1.744 + uint64_t buffer; 1.745 + uint16_t code_size; 1.746 + uint64_t code_end_delta; 1.747 + uint64_t constMethod; 1.748 + int8_t access_flags; 1.749 + int32_t best_bci = 0; 1.750 + int32_t stream_bci = 0; 1.751 + int32_t stream_line = 0; 1.752 + int32_t err; 1.753 + 1.754 + if (debug > 2) { 1.755 + char name[256]; 1.756 + err = name_for_methodPtr(J, vf->method, name, 256); 1.757 + CHECK_FAIL(err); 1.758 + fprintf(stderr, "\t line_number_from_bci: BEGIN, method name: %s, targ bci: %d\n", 1.759 + name, vf->bci); 1.760 + } 1.761 + 1.762 + err = read_pointer(J, vf->method + OFFSET_Method_constMethod, &constMethod); 1.763 + CHECK_FAIL(err); 1.764 + 1.765 + vf->line = 0; 1.766 + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_flags, &access_flags, sizeof(int8_t)); 1.767 + CHECK_FAIL(err); 1.768 + 1.769 + if (!(access_flags & ConstMethod_has_linenumber_table)) { 1.770 + if (debug > 2) 1.771 + fprintf(stderr, "\t line_number_from_bci: END: !HAS_LINE_NUMBER_TABLE \n\n"); 1.772 + return PS_OK; 1.773 + } 1.774 + 1.775 + /* The line numbers are a short array of 2-tuples [start_pc, line_number]. 1.776 + * Not necessarily sorted and not necessarily one-to-one. 1.777 + */ 1.778 + 1.779 + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_code_size, &code_size, SZ16); 1.780 + CHECK_FAIL(err); 1.781 + 1.782 + /* inlined_table_start() */ 1.783 + code_end_delta = (uint64_t) (access_flags & AccessFlags_NATIVE) ? 2*POINTER_SIZE : 0; 1.784 + buffer = constMethod + (uint64_t) SIZE_ConstMethod + (uint64_t) code_size + code_end_delta; 1.785 + 1.786 + if (debug > 2) { 1.787 + fprintf(stderr, "\t\t line_number_from_bci: method: %#llx, native: %d\n", 1.788 + vf->method, (access_flags & AccessFlags_NATIVE)); 1.789 + fprintf(stderr, "\t\t line_number_from_bci: buffer: %#llx, code_size: %d\n", 1.790 + buffer, (int) code_size); 1.791 + } 1.792 + 1.793 + while (read_pair(J, &buffer, &stream_bci, &stream_line) == 0) { 1.794 + if (stream_bci == vf->bci) { 1.795 + /* perfect match */ 1.796 + if (debug > 2) 1.797 + fprintf(stderr, "\t line_number_from_bci: END: exact line: %ld \n\n", vf->line); 1.798 + vf->line = stream_line; 1.799 + return PS_OK; 1.800 + } else { 1.801 + /* update best_bci/line */ 1.802 + if (stream_bci < vf->bci && stream_bci >= best_bci) { 1.803 + best_bci = stream_bci; 1.804 + vf->line = stream_line; 1.805 + if (debug > 2) { 1.806 + fprintf(stderr, "\t line_number_from_bci: best_bci: %ld, best_line: %ld\n", 1.807 + best_bci, vf->line); 1.808 + } 1.809 + } 1.810 + } 1.811 + } 1.812 + if (debug > 2) 1.813 + fprintf(stderr, "\t line_number_from_bci: END: line: %ld \n\n", vf->line); 1.814 + return PS_OK; 1.815 + 1.816 + fail: 1.817 + if (debug) 1.818 + fprintf(stderr, "\t line_number_from_bci: FAIL\n"); 1.819 + return err; 1.820 +} 1.821 + 1.822 +static int 1.823 +get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc) 1.824 +{ 1.825 + int32_t pc_offset; 1.826 + int32_t err; 1.827 + 1.828 + err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32); 1.829 + CHECK_FAIL(err); 1.830 + 1.831 + *real_pc = N->nm + N->instrs_beg + pc_offset; 1.832 + if (debug > 2) { 1.833 + fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n", 1.834 + pc_offset, *real_pc); 1.835 + } 1.836 + return PS_OK; 1.837 + 1.838 + fail: 1.839 + return err; 1.840 +} 1.841 + 1.842 +/* Finds a PcDesc with real-pc equal to N->pc */ 1.843 +static int pc_desc_at(Nmethod_t *N) 1.844 +{ 1.845 + uint64_t pc_diff; 1.846 + int32_t offs; 1.847 + int32_t err; 1.848 + 1.849 + if (debug > 2) 1.850 + fprintf(stderr, "\t pc_desc_at: BEGIN\n"); 1.851 + 1.852 + N->vf_cnt = 0; 1.853 + N->pc_desc = 0; 1.854 + 1.855 + for (offs = N->scopes_pcs_beg; offs < N->scopes_pcs_end; offs += SIZE_PcDesc) { 1.856 + uint64_t pd; 1.857 + uint64_t best_pc_diff = 16; /* some approximation */ 1.858 + uint64_t real_pc = 0; 1.859 + 1.860 + pd = N->nm + offs; 1.861 + err = get_real_pc(N, pd, &real_pc); 1.862 + CHECK_FAIL(err); 1.863 + 1.864 + pc_diff = real_pc - N->pc; 1.865 + 1.866 + /* In general, this fragment should work */ 1.867 + if (pc_diff == 0) { 1.868 + N->pc_desc = pd; 1.869 + if (debug) { 1.870 + fprintf(stderr, "\t pc_desc_at: END: pc_desc: FOUND: %#lx \n\n", pd); 1.871 + } 1.872 + return PS_OK; 1.873 + } 1.874 + /* This fragment is to be able to find out an appropriate 1.875 + * pc_desc entry even if pc_desc info is inaccurate. 1.876 + */ 1.877 + if (best_pc_diff > pc_diff && pc_diff > 0) { 1.878 + best_pc_diff = pc_diff; 1.879 + N->pc_desc = pd; 1.880 + } 1.881 + } 1.882 + if (debug) { 1.883 + fprintf(stderr, "\t pc_desc_at: END: pc_desc NOT FOUND"); 1.884 + if (pc_diff < 20) 1.885 + fprintf(stderr, ", best pc_diff: %d\n\n", pc_diff); 1.886 + else 1.887 + fprintf(stderr, "\n\n"); 1.888 + } 1.889 + return PS_OK; 1.890 + 1.891 + fail: 1.892 + return err; 1.893 +} 1.894 + 1.895 +static int 1.896 +scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf) 1.897 +{ 1.898 + uint64_t buffer; 1.899 + int32_t err; 1.900 + 1.901 + if (debug > 2) { 1.902 + fprintf(stderr, "\t\t scope_desc_at: BEGIN \n"); 1.903 + } 1.904 + 1.905 + buffer = N->nm + N->scopes_data_beg + decode_offset; 1.906 + 1.907 + err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset); 1.908 + CHECK_FAIL(err); 1.909 + 1.910 + err = raw_read_int(N->J, &buffer, &vf->methodIdx); 1.911 + CHECK_FAIL(err); 1.912 + 1.913 + err = raw_read_int(N->J, &buffer, &vf->bci); 1.914 + CHECK_FAIL(err); 1.915 + 1.916 + if (debug > 2) { 1.917 + fprintf(stderr, "\t\t scope_desc_at: sender_decode_offset: %#x\n", 1.918 + vf->sender_decode_offset); 1.919 + fprintf(stderr, "\t\t scope_desc_at: methodIdx: %d\n", vf->methodIdx); 1.920 + fprintf(stderr, "\t\t scope_desc_at: bci: %d\n", vf->bci); 1.921 + 1.922 + fprintf(stderr, "\t\t scope_desc_at: END \n\n"); 1.923 + } 1.924 + return PS_OK; 1.925 + 1.926 + fail: 1.927 + return err; 1.928 +} 1.929 + 1.930 +static int scopeDesc_chain(Nmethod_t *N) { 1.931 + int32_t decode_offset = 0; 1.932 + int32_t err; 1.933 + 1.934 + if (debug > 2) { 1.935 + fprintf(stderr, "\t scopeDesc_chain: BEGIN\n"); 1.936 + } 1.937 + 1.938 + err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset, 1.939 + &decode_offset, SZ32); 1.940 + CHECK_FAIL(err); 1.941 + 1.942 + while (decode_offset > 0) { 1.943 + Vframe_t *vf = &N->vframes[N->vf_cnt]; 1.944 + 1.945 + if (debug > 2) { 1.946 + fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset); 1.947 + } 1.948 + 1.949 + err = scope_desc_at(N, decode_offset, vf); 1.950 + CHECK_FAIL(err); 1.951 + 1.952 + if (vf->methodIdx > ((N->metadata_end - N->metadata_beg) / POINTER_SIZE)) { 1.953 + fprintf(stderr, "\t scopeDesc_chain: (methodIdx > metadata length) !\n"); 1.954 + return -1; 1.955 + } 1.956 + err = read_pointer(N->J, N->nm + N->metadata_beg + (vf->methodIdx-1)*POINTER_SIZE, 1.957 + &vf->method); 1.958 + CHECK_FAIL(err); 1.959 + 1.960 + if (vf->method) { 1.961 + N->vf_cnt++; 1.962 + err = line_number_from_bci(N->J, vf); 1.963 + CHECK_FAIL(err); 1.964 + if (debug > 2) { 1.965 + fprintf(stderr, "\t scopeDesc_chain: method: %#8llx, line: %ld\n", 1.966 + vf->method, vf->line); 1.967 + } 1.968 + } 1.969 + decode_offset = vf->sender_decode_offset; 1.970 + } 1.971 + if (debug > 2) { 1.972 + fprintf(stderr, "\t scopeDesc_chain: END \n\n"); 1.973 + } 1.974 + return PS_OK; 1.975 + 1.976 + fail: 1.977 + if (debug) { 1.978 + fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n"); 1.979 + } 1.980 + return err; 1.981 +} 1.982 + 1.983 + 1.984 +static int 1.985 +name_for_nmethod(jvm_agent_t* J, 1.986 + uint64_t nm, 1.987 + uint64_t pc, 1.988 + uint64_t method, 1.989 + char *result, 1.990 + size_t size, 1.991 + Jframe_t *jframe 1.992 +) { 1.993 + Nmethod_t *N; 1.994 + Vframe_t *vf; 1.995 + int32_t err; 1.996 + int deoptimized = 0; 1.997 + 1.998 + if (debug) { 1.999 + fprintf(stderr, "name_for_nmethod: BEGIN: nmethod: %#llx, pc: %#llx\n", nm, pc); 1.1000 + } 1.1001 + if (J->N == NULL) { 1.1002 + J->N = (Nmethod_t *) malloc(sizeof(Nmethod_t)); 1.1003 + } 1.1004 + memset(J->N, 0, sizeof(Nmethod_t)); /* Initial stat: all values are zeros */ 1.1005 + N = J->N; 1.1006 + N->J = J; 1.1007 + N->nm = nm; 1.1008 + N->pc = pc; 1.1009 + N->jframe = jframe; 1.1010 + 1.1011 + err = nmethod_info(N); 1.1012 + CHECK_FAIL(err); 1.1013 + if (debug) { 1.1014 + fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n", 1.1015 + pc, N->nm + N->deopt_beg); 1.1016 + } 1.1017 + 1.1018 + /* check for a deoptimized frame */ 1.1019 + if ( pc == N->nm + N->deopt_beg) { 1.1020 + uint64_t base; 1.1021 + if (debug) { 1.1022 + fprintf(stderr, "name_for_nmethod: found deoptimized frame\n"); 1.1023 + } 1.1024 + if (J->prev_fr.sender_sp != 0) { 1.1025 + base = J->prev_fr.sender_sp + N->orig_pc_offset; 1.1026 + } else { 1.1027 + base = J->curr_fr.sp + N->orig_pc_offset; 1.1028 + } 1.1029 + err = read_pointer(J, base, &N->pc); 1.1030 + CHECK_FAIL(err); 1.1031 + if (debug) { 1.1032 + fprintf(stderr, "name_for_nmethod: found deoptimized frame converting pc from %#8llx to %#8llx\n", 1.1033 + pc, N->pc); 1.1034 + } 1.1035 + deoptimized = 1; 1.1036 + } 1.1037 + 1.1038 + err = pc_desc_at(N); 1.1039 + CHECK_FAIL(err); 1.1040 + 1.1041 + if (N->pc_desc > 0) { 1.1042 + jframe->locinf = 1; 1.1043 + err = scopeDesc_chain(N); 1.1044 + CHECK_FAIL(err); 1.1045 + } 1.1046 + result[0] = COMP_METHOD_SIGN; 1.1047 + vf = &N->vframes[0]; 1.1048 + if (N->vf_cnt > 0) { 1.1049 + jframe->vf_cnt = N->vf_cnt; 1.1050 + jframe->bci = vf->bci; 1.1051 + jframe->line = vf->line; 1.1052 + err = name_for_methodPtr(J, N->vframes[0].method, result+1, size-1); 1.1053 + CHECK_FAIL(err); 1.1054 + } else { 1.1055 + err = name_for_methodPtr(J, method, result+1, size-1); 1.1056 + CHECK_FAIL(err); 1.1057 + } 1.1058 + if (deoptimized) { 1.1059 + strncat(result + 1, " [deoptimized frame]; ", size-1); 1.1060 + } else { 1.1061 + strncat(result + 1, " [compiled] ", size-1); 1.1062 + } 1.1063 + if (debug) 1.1064 + fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n", 1.1065 + result, N->vf_cnt); 1.1066 + return PS_OK; 1.1067 + 1.1068 + fail: 1.1069 + if (debug) 1.1070 + fprintf(stderr, "name_for_nmethod: FAIL \n\n"); 1.1071 + return err; 1.1072 +} 1.1073 + 1.1074 +int is_bci(intptr_t bcx) { 1.1075 + switch (DATA_MODEL) { 1.1076 + case PR_MODEL_LP64: 1.1077 + return ((uintptr_t) bcx) <= ((uintptr_t) MAX_METHOD_CODE_SIZE) ; 1.1078 + case PR_MODEL_ILP32: 1.1079 + default: 1.1080 + return 0 <= bcx && bcx <= MAX_METHOD_CODE_SIZE; 1.1081 + } 1.1082 +} 1.1083 + 1.1084 +static int 1.1085 +name_for_imethod(jvm_agent_t* J, 1.1086 + uint64_t bcx, 1.1087 + uint64_t method, 1.1088 + char *result, 1.1089 + size_t size, 1.1090 + Jframe_t *jframe 1.1091 +) { 1.1092 + uint64_t bci; 1.1093 + uint64_t constMethod; 1.1094 + Vframe_t vframe = {0}; 1.1095 + Vframe_t *vf = &vframe; 1.1096 + int32_t err; 1.1097 + 1.1098 + err = read_pointer(J, method + OFFSET_Method_constMethod, &constMethod); 1.1099 + CHECK_FAIL(err); 1.1100 + 1.1101 + bci = is_bci(bcx) ? bcx : bcx - (constMethod + (uint64_t) SIZE_ConstMethod); 1.1102 + 1.1103 + if (debug) 1.1104 + fprintf(stderr, "\t name_for_imethod: BEGIN: method: %#llx\n", method); 1.1105 + 1.1106 + err = name_for_methodPtr(J, method, result, size); 1.1107 + CHECK_FAIL(err); 1.1108 + if (debug) 1.1109 + fprintf(stderr, "\t name_for_imethod: method name: %s\n", result); 1.1110 + 1.1111 + if (bci > 0) { 1.1112 + vf->method = method; 1.1113 + vf->bci = bci; 1.1114 + err = line_number_from_bci(J, vf); 1.1115 + CHECK_FAIL(err); 1.1116 + } 1.1117 + jframe->bci = vf->bci; 1.1118 + jframe->line = vf->line; 1.1119 + jframe->locinf = 1; 1.1120 + 1.1121 + if (debug) { 1.1122 + fprintf(stderr, "\t name_for_imethod: END: bci: %d, line: %d\n\n", 1.1123 + vf->bci, vf->line); 1.1124 + } 1.1125 + return PS_OK; 1.1126 + 1.1127 + fail: 1.1128 + if (debug) 1.1129 + fprintf(stderr, "\t name_for_imethod: FAIL\n"); 1.1130 + return err; 1.1131 +} 1.1132 + 1.1133 +static int 1.1134 +name_for_codecache(jvm_agent_t* J, uint64_t fp, uint64_t pc, char * result, 1.1135 + size_t size, Jframe_t *jframe, int* is_interpreted) 1.1136 +{ 1.1137 + uint64_t start; 1.1138 + uint64_t vtbl; 1.1139 + int32_t err; 1.1140 + *is_interpreted = 0; 1.1141 + 1.1142 + result[0] = '\0'; 1.1143 + 1.1144 + err = find_start(J, pc, &start); 1.1145 + CHECK_FAIL(err); 1.1146 + 1.1147 + err = read_pointer(J, start, &vtbl); 1.1148 + CHECK_FAIL(err); 1.1149 + 1.1150 + if (vtbl == J->nmethod_vtbl) { 1.1151 + uint64_t method; 1.1152 + 1.1153 + err = read_pointer(J, start + OFFSET_nmethod_method, &method); 1.1154 + CHECK_FAIL(err); 1.1155 + 1.1156 + if (debug) { 1.1157 + fprintf(stderr, "name_for_codecache: start: %#8llx, pc: %#8llx, method: %#8llx \n", 1.1158 + start, pc, method); 1.1159 + } 1.1160 + err = name_for_nmethod(J, start, pc, method, result, size, jframe); 1.1161 + CHECK_FAIL(err); 1.1162 + } else if (vtbl == J->BufferBlob_vtbl) { 1.1163 + const char * name; 1.1164 + 1.1165 + err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name); 1.1166 + 1.1167 + /* 1.1168 + * Temporary usage of string "Interpreter". 1.1169 + * We need some other way to distinguish "StubRoutines" 1.1170 + * and regular interpreted frames. 1.1171 + */ 1.1172 + if (err == PS_OK && strncmp(name, "Interpreter", 11) == 0) { 1.1173 + *is_interpreted = 1; 1.1174 + if (is_method(J, J->methodPtr)) { 1.1175 + return name_for_imethod(J, J->bcx, J->methodPtr, result, size, jframe); 1.1176 + } 1.1177 + } 1.1178 + 1.1179 + if (err == PS_OK) { 1.1180 + strncpy(result, name, size); 1.1181 + free((void*)name); 1.1182 + } else { 1.1183 + strncpy(result, "<unknown BufferBlob>", size); 1.1184 + } 1.1185 + /* return PS_OK; */ 1.1186 + } else { 1.1187 + const char * name; 1.1188 + 1.1189 + err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name); 1.1190 + if (err == PS_OK) { 1.1191 + strncpy(result, name, size); 1.1192 + free((void*)name); 1.1193 + } else { 1.1194 + strncpy(result, "<unknown CodeBlob>", size); 1.1195 + WARN1("unknown CodeBlob: vtbl = 0x%x", vtbl); 1.1196 + } 1.1197 + } 1.1198 + result[size-1] = '\0'; 1.1199 + 1.1200 +#ifdef X86_COMPILER2 1.1201 + if (vtbl != J->RuntimeStub_vtbl) { 1.1202 + uint64_t trial_pc; 1.1203 + int frame_size; 1.1204 + err = ps_pread(J->P, start + OFFSET_CodeBlob_frame_size, 1.1205 + &frame_size, SZ32); 1.1206 + CHECK_FAIL(err); 1.1207 + 1.1208 + // frame_size is in words, we want bytes. 1.1209 + frame_size *= POINTER_SIZE; /* word => byte conversion */ 1.1210 + 1.1211 + /* 1.1212 + Because c2 doesn't use FP as a framepointer the value of sp/fp we receive 1.1213 + in the initial entry to a set of stack frames containing server frames 1.1214 + will pretty much be nonsense. We can detect that nonsense by looking to 1.1215 + see if the PC we received is correct if we look at the expected storage 1.1216 + location in relation to the FP (ie. POINTER_SIZE(FP) ) 1.1217 + */ 1.1218 + 1.1219 + err = read_pointer(J, fp + POINTER_SIZE , &trial_pc); 1.1220 + if ( (err != PS_OK || trial_pc != pc) && frame_size > 0 ) { 1.1221 + // Either we couldn't even read at the "fp" or the pc didn't match 1.1222 + // both are sure clues that the fp is bogus. We no search the stack 1.1223 + // for a reasonable number of words trying to find the bogus fp 1.1224 + // and the current pc in adjacent words. The we will be able to 1.1225 + // deduce an approximation of the frame pointer and actually get 1.1226 + // the correct stack pointer. Which we can then unwind for the 1.1227 + // next frame. 1.1228 + int i; 1.1229 + uint64_t check; 1.1230 + uint64_t base = J->curr_fr.sp; 1.1231 + uint64_t prev_fp = 0; 1.1232 + for ( i = 0; i < frame_size * 5 ; i++, base += POINTER_SIZE ) { 1.1233 + err = read_pointer(J, base , &check); 1.1234 + CHECK_FAIL(err); 1.1235 + if (check == fp) { 1.1236 + base += POINTER_SIZE; 1.1237 + err = read_pointer(J, base , &check); 1.1238 + CHECK_FAIL(err); 1.1239 + if (check == pc) { 1.1240 + if (debug) { 1.1241 + fprintf(stderr, "name_for_codecache: found matching fp/pc combo at 0x%llx\n", base - POINTER_SIZE); 1.1242 + } 1.1243 + prev_fp = base - 2 * POINTER_SIZE; 1.1244 + break; 1.1245 + } 1.1246 + } 1.1247 + } 1.1248 + if ( prev_fp != 0 ) { 1.1249 + // real_sp is the sp we should have received for this frame 1.1250 + uint64_t real_sp = prev_fp + 2 * POINTER_SIZE; 1.1251 + // +POINTER_SIZE because callee owns the return address so caller's sp is +1 word 1.1252 + jframe->new_sp = real_sp + frame_size + POINTER_SIZE; 1.1253 + err = read_pointer(J, jframe->new_sp - POINTER_SIZE , &jframe->new_pc); 1.1254 + CHECK_FAIL(err); 1.1255 + err = read_pointer(J, jframe->new_sp - 2*POINTER_SIZE, &jframe->new_fp); 1.1256 + CHECK_FAIL(err); 1.1257 + return PS_OK; 1.1258 + } 1.1259 + } 1.1260 + 1.1261 + /* A prototype to workaround FP absence */ 1.1262 + /* 1.1263 + * frame_size can be 0 for StubRoutines (1) frame. 1.1264 + * In this case it should work with fp as usual. 1.1265 + */ 1.1266 + if (frame_size > 0) { 1.1267 + jframe->new_fp = J->prev_fr.fp + frame_size; 1.1268 + jframe->new_sp = jframe->new_fp + 2 * POINTER_SIZE; 1.1269 + } else { 1.1270 + memset(&J->curr_fr, 0, sizeof(Frame_t)); 1.1271 + err = read_pointer(J, fp, &jframe->new_fp); 1.1272 + CHECK_FAIL(err); 1.1273 + 1.1274 + err = read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc); 1.1275 + CHECK_FAIL(err); 1.1276 + } 1.1277 + if (debug) { 1.1278 + fprintf(stderr, "name_for_codecache: %s, frame_size=%#lx\n", 1.1279 + result, frame_size); 1.1280 + fprintf(stderr, "name_for_codecache: prev_fr.fp=%#lx, fp=%#lx\n", 1.1281 + J->prev_fr.fp, jframe->new_fp); 1.1282 + } 1.1283 + } 1.1284 +#endif /* X86_COMPILER2 */ 1.1285 + 1.1286 + return PS_OK; 1.1287 + 1.1288 + fail: 1.1289 + return err; 1.1290 +} 1.1291 + 1.1292 +int Jget_vframe(jvm_agent_t* J, int vframe_no, 1.1293 + char *name, size_t size, Jframe_t *jframe) 1.1294 +{ 1.1295 + Nmethod_t *N = J->N; 1.1296 + Vframe_t *vf; 1.1297 + int32_t err; 1.1298 + 1.1299 + if (vframe_no >= N->vf_cnt) { 1.1300 + (void) sprintf(name, "Wrong inlinedMethod%1d()", vframe_no); 1.1301 + return -1; 1.1302 + } 1.1303 + vf = N->vframes + vframe_no; 1.1304 + name[0] = COMP_METHOD_SIGN; 1.1305 + err = name_for_methodPtr(J, vf->method, name + 1, size); 1.1306 + CHECK_FAIL(err); 1.1307 + 1.1308 + jframe->bci = vf->bci; 1.1309 + jframe->line = vf->line; 1.1310 + if (debug) { 1.1311 + fprintf(stderr, "\t Jget_vframe: method name: %s, line: %ld\n", 1.1312 + name, vf->line); 1.1313 + } 1.1314 + return PS_OK; 1.1315 + 1.1316 + fail: 1.1317 + if (debug) { 1.1318 + fprintf(stderr, "\t Jget_vframe: FAIL\n"); 1.1319 + } 1.1320 + return err; 1.1321 +} 1.1322 + 1.1323 +#define MAX_SYM_SIZE 256 1.1324 + 1.1325 +int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name, 1.1326 + size_t size, Jframe_t *jframe) { 1.1327 + uintptr_t fp; 1.1328 + uintptr_t pc; 1.1329 + /* arguments given to read_pointer need to be worst case sized */ 1.1330 + uint64_t methodPtr = 0; 1.1331 + uint64_t sender_sp; 1.1332 + uint64_t bcx = 0; 1.1333 + int is_interpreted = 0; 1.1334 + int result = PS_OK; 1.1335 + int err = PS_OK; 1.1336 + 1.1337 + if (J == NULL) { 1.1338 + return -1; 1.1339 + } 1.1340 + 1.1341 + jframe->vf_cnt = 1; 1.1342 + jframe->new_fp = 0; 1.1343 + jframe->new_pc = 0; 1.1344 + jframe->line = 0; 1.1345 + jframe->bci = 0; 1.1346 + jframe->locinf = 0; 1.1347 + 1.1348 + read_volatiles(J); 1.1349 + pc = (uintptr_t) regs[R_PC]; 1.1350 + J->curr_fr.pc = pc; 1.1351 + J->curr_fr.fp = regs[R_FP]; 1.1352 + J->curr_fr.sp = regs[R_SP]; 1.1353 + 1.1354 + if (debug) 1.1355 + fprintf(stderr, "Jlookup_by_regs: BEGINs: fp=%#lx, pc=%#lx\n", regs[R_FP], pc); 1.1356 + 1.1357 +#if defined(sparc) || defined(__sparc) 1.1358 + /* The following workaround is for SPARC. CALL instruction occupates 8 bytes. 1.1359 + * In the pcDesc structure return pc offset is recorded for CALL instructions. 1.1360 + * regs[R_PC] contains a CALL instruction pc offset. 1.1361 + */ 1.1362 + pc += 8; 1.1363 + bcx = (uintptr_t) regs[R_L1]; 1.1364 + methodPtr = (uintptr_t) regs[R_L2]; 1.1365 + sender_sp = regs[R_I5]; 1.1366 + if (debug > 2) { 1.1367 + fprintf(stderr, "\nregs[R_I1]=%lx, regs[R_I2]=%lx, regs[R_I5]=%lx, regs[R_L1]=%lx, regs[R_L2]=%lx\n", 1.1368 + regs[R_I1], regs[R_I2], regs[R_I5], regs[R_L1], regs[R_L2]); 1.1369 + } 1.1370 +#elif defined(i386) || defined(__i386) || defined(__amd64) 1.1371 + 1.1372 + fp = (uintptr_t) regs[R_FP]; 1.1373 + if (J->prev_fr.fp == 0) { 1.1374 +#ifdef X86_COMPILER2 1.1375 + /* A workaround for top java frames */ 1.1376 + J->prev_fr.fp = (uintptr_t)(regs[R_SP] - 2 * POINTER_SIZE); 1.1377 +#else 1.1378 + J->prev_fr.fp = (uintptr_t)(regs[R_SP] - POINTER_SIZE); 1.1379 +#endif /* COMPILER2 */ 1.1380 + } 1.1381 + if (debug > 2) { 1.1382 + printf("Jlookup_by_regs: J->prev_fr.fp = %#lx\n", J->prev_fr.fp); 1.1383 + } 1.1384 + 1.1385 + if (read_pointer(J, fp + OFFSET_interpreter_frame_method, &methodPtr) != PS_OK) { 1.1386 + methodPtr = 0; 1.1387 + } 1.1388 + if (read_pointer(J, fp + OFFSET_interpreter_frame_sender_sp, &sender_sp) != PS_OK) { 1.1389 + sender_sp = 0; 1.1390 + } 1.1391 + if (read_pointer(J, fp + OFFSET_interpreter_frame_bcx_offset, &bcx) != PS_OK) { 1.1392 + bcx = 0; 1.1393 + } 1.1394 +#endif /* i386 */ 1.1395 + 1.1396 + J->methodPtr = methodPtr; 1.1397 + J->bcx = bcx; 1.1398 + 1.1399 + /* On x86 with C2 JVM: native frame may have wrong regs[R_FP] 1.1400 + * For example: JVM_SuspendThread frame poins to the top interpreted frame. 1.1401 + * If we call is_method(J, methodPtr) before codecache_contains(J, pc) 1.1402 + * then we go over and omit both: nmethod and I2CAdapter frames. 1.1403 + * Note, that regs[R_PC] is always correct if frame defined correctly. 1.1404 + * So it is better to call codecache_contains(J, pc) from the beginning. 1.1405 + */ 1.1406 +#ifndef X86_COMPILER2 1.1407 + if (is_method(J, J->methodPtr)) { 1.1408 + result = name_for_imethod(J, bcx, J->methodPtr, name, size, jframe); 1.1409 + /* If the methodPtr is a method then this is highly likely to be 1.1410 + an interpreter frame */ 1.1411 + if (result >= 0) { 1.1412 + is_interpreted = 1; 1.1413 + } 1.1414 + } else 1.1415 +#endif /* ! X86_COMPILER2 */ 1.1416 + 1.1417 + if (codecache_contains(J, pc)) { 1.1418 + result = name_for_codecache(J, fp, pc, name, size, jframe, &is_interpreted); 1.1419 + } 1.1420 +#ifdef X86_COMPILER2 1.1421 + else if (is_method(J, J->methodPtr)) { 1.1422 + result = name_for_imethod(J, bcx, J->methodPtr, name, size, jframe); 1.1423 + /* If the methodPtr is a method then this is highly likely to be 1.1424 + an interpreter frame */ 1.1425 + if (result >= 0) { 1.1426 + is_interpreted = 1; 1.1427 + } 1.1428 + } 1.1429 +#endif /* X86_COMPILER2 */ 1.1430 + else { 1.1431 + if (debug) { 1.1432 + fprintf(stderr, "Jlookup_by_regs: END with -1\n\n"); 1.1433 + } 1.1434 + result = -1; 1.1435 + } 1.1436 + if (!is_interpreted) { 1.1437 + sender_sp = 0; 1.1438 + } 1.1439 + J->curr_fr.sender_sp = sender_sp; 1.1440 + 1.1441 +#ifdef X86_COMPILER2 1.1442 + if (!J->curr_fr.fp) { 1.1443 + J->curr_fr.fp = (jframe->new_fp) ? jframe->new_fp : (uintptr_t)regs[R_FP]; 1.1444 + } 1.1445 + if (!jframe->new_pc && jframe->new_fp) { 1.1446 + // This seems dubious 1.1447 + read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc); 1.1448 + CHECK_FAIL(err); 1.1449 + if (debug > 2) { 1.1450 + printf("Jlookup_by_regs: (update pc) jframe->new_fp: %#llx, jframe->new_pc: %#llx\n", 1.1451 + jframe->new_fp, jframe->new_pc); 1.1452 + } 1.1453 + } 1.1454 + 1.1455 +#endif /* X86_COMPILER2 */ 1.1456 + J->prev_fr = J->curr_fr; 1.1457 + 1.1458 + if (debug) 1.1459 + fprintf(stderr, "Jlookup_by_regs: END\n\n"); 1.1460 + 1.1461 + return result; 1.1462 + 1.1463 + fail: 1.1464 + return err; 1.1465 +} 1.1466 + 1.1467 +void update_gregs(prgregset_t gregs, Jframe_t jframe) { 1.1468 +#ifdef X86_COMPILER2 1.1469 + if (debug > 0) { 1.1470 + 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]); 1.1471 + } 1.1472 + /* 1.1473 + * A workaround for java C2 frames with unconventional FP. 1.1474 + * may have to modify regset with new values for FP/PC/SP when needed. 1.1475 + */ 1.1476 + if (jframe.new_sp) { 1.1477 + *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) jframe.new_sp; 1.1478 + } else { 1.1479 + // *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) gregs[R_FP] + 2 * POINTER_SIZE; 1.1480 + } 1.1481 + 1.1482 + if (jframe.new_fp) { 1.1483 + *((uintptr_t *) &gregs[R_FP]) = (uintptr_t) jframe.new_fp; 1.1484 + } 1.1485 + if (jframe.new_pc) { 1.1486 + *((uintptr_t *) &gregs[R_PC]) = (uintptr_t) jframe.new_pc; 1.1487 + } 1.1488 + if (debug > 0) { 1.1489 + 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]); 1.1490 + } 1.1491 +#endif /* X86_COMPILER2 */ 1.1492 +} 1.1493 + 1.1494 +/* 1.1495 + * Iterates over java frames at current location given by 'gregs'. 1.1496 + * 1.1497 + * Returns -1 if no java frames are present or if an error is encountered. 1.1498 + * Returns the result of calling 'func' if the return value is non-zero. 1.1499 + * Returns 0 otherwise. 1.1500 + */ 1.1501 +int Jframe_iter(jvm_agent_t *J, prgregset_t gregs, java_stack_f *func, void* cld) { 1.1502 + char buf[MAX_SYM_SIZE + 1]; 1.1503 + Jframe_t jframe; 1.1504 + int i = 0, res; 1.1505 +#ifdef X86_COMPILER2 1.1506 + if (debug > 0) { 1.1507 + fprintf(stderr, "Jframe_iter: Entry sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); 1.1508 + } 1.1509 +#endif /* X86_COMPILER2 */ 1.1510 + 1.1511 + memset(&jframe, 0, sizeof(Jframe_t)); 1.1512 + memset(buf, 0, sizeof(buf)); 1.1513 + res = Jlookup_by_regs(J, gregs, buf, sizeof(buf), &jframe); 1.1514 + if (res != PS_OK) 1.1515 + return (-1); 1.1516 + 1.1517 + 1.1518 + res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1, 1.1519 + jframe.line, NULL); 1.1520 + if (res != 0) { 1.1521 + update_gregs(gregs, jframe); 1.1522 + return (res); 1.1523 + } 1.1524 + for (i = 1; i < jframe.vf_cnt; i++) { 1.1525 + Jget_vframe(J, i, buf, sizeof(buf), &jframe); 1.1526 + res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1, 1.1527 + jframe.line, NULL); 1.1528 + if (res != 0) { 1.1529 + update_gregs(gregs, jframe); 1.1530 + return (res); 1.1531 + } 1.1532 + } 1.1533 + update_gregs(gregs, jframe); 1.1534 + return (0); 1.1535 +}