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