src/os/bsd/dtrace/libjvm_db.c

Fri, 03 Apr 2020 14:14:26 +0100

author
aph
date
Fri, 03 Apr 2020 14:14:26 +0100
changeset 9920
3a3803a0c789
parent 6948
fd94cbe7c5da
child 9931
fd44df5e3bc3
permissions
-rw-r--r--

8076475: Misuses of strncpy/strncat
Summary: Various small fixes around strncpy and strncat
Reviewed-by: andrew

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

mercurial