Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/solaris/dtrace/libjvm_db.c
32284 views
/*1* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include <stdio.h>25#include <stdlib.h>26#include <string.h>27#include <errno.h>28#include <gelf.h>2930#include "libjvm_db.h"31#include "JvmOffsets.h"3233#define LIBJVM_SO "libjvm.so"3435#if defined(i386) || defined(__i386) || defined(__amd64)36#ifdef COMPILER237#define X86_COMPILER238#endif /* COMPILER2 */39#endif /* i386 */4041typedef struct {42short vf_cnt; /* number of recognized java vframes */43short bci; /* current frame method byte code index */44int line; /* current frame method source line */45uint64_t new_fp; /* fp for the next frame */46uint64_t new_pc; /* pc for the next frame */47uint64_t new_sp; /* "raw" sp for the next frame (includes extension by interpreter/adapter */48char locinf; /* indicates there is valid location info */49} Jframe_t;5051int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,52size_t size, Jframe_t *jframe);5354int main(int arg) { return arg; }5556static int debug = 0;5758static void failed(int err, const char * file, int line) {59if (debug) {60fprintf(stderr, "failed %d at %s:%d\n", err, file, line);61}62}6364static void warn(const char * file, int line, const char * msg) {65if (debug) {66fprintf(stderr, "warning: %s at %s:%d\n", msg, file, line);67}68}6970static void warn1(const char * file, int line, const char * msg, intptr_t arg1) {71if (debug) {72fprintf(stderr, "warning: ");73fprintf(stderr, msg, arg1);74fprintf(stderr, " at %s:%d\n", file, line);75}76}7778#define CHECK_FAIL(err) \79if (err != PS_OK) { failed(err, __FILE__, __LINE__); goto fail; }80#define WARN(msg) warn(__FILE__, __LINE__, msg)81#define WARN1(msg, arg1) warn1(__FILE__, __LINE__, msg, arg1)8283typedef struct VMStructEntry {84const char * typeName; /* The type name containing the given field (example: "Klass") */85const char * fieldName; /* The field name within the type (example: "_name") */86uint64_t address; /* Address of field; only used for static fields */87/* ("offset" can not be reused because of apparent SparcWorks compiler bug */88/* in generation of initializer data) */89} VMStructEntry;9091/* Prototyping inlined methods */9293int sprintf(char *s, const char *format, ...);9495#define SZ16 sizeof(int16_t)96#define SZ32 sizeof(int32_t)9798#define COMP_METHOD_SIGN '*'99100#define MAX_VFRAMES_CNT 256101102typedef struct vframe {103uint64_t method;104int32_t sender_decode_offset;105int32_t methodIdx;106int32_t bci;107int32_t line;108} Vframe_t;109110typedef struct frame {111uintptr_t fp;112uintptr_t pc;113uintptr_t sp;114uintptr_t sender_sp; // The unextended sp of the caller115} Frame_t;116117typedef struct Nmethod_t {118struct jvm_agent* J;119Jframe_t *jframe;120121uint64_t nm; /* _nmethod */122uint64_t pc;123uint64_t pc_desc;124125int32_t orig_pc_offset; /* _orig_pc_offset */126int32_t instrs_beg; /* _code_offset */127int32_t instrs_end;128int32_t deopt_beg; /* _deoptimize_offset */129int32_t scopes_data_beg; /* _scopes_data_offset */130int32_t scopes_data_end;131int32_t metadata_beg; /* _metadata_offset */132int32_t metadata_end;133int32_t scopes_pcs_beg; /* _scopes_pcs_offset */134int32_t scopes_pcs_end;135136int vf_cnt;137Vframe_t vframes[MAX_VFRAMES_CNT];138} Nmethod_t;139140struct jvm_agent {141struct ps_prochandle* P;142143uint64_t nmethod_vtbl;144uint64_t CodeBlob_vtbl;145uint64_t BufferBlob_vtbl;146uint64_t RuntimeStub_vtbl;147uint64_t Method_vtbl;148149uint64_t Use_Compressed_Oops_address;150uint64_t Universe_narrow_oop_base_address;151uint64_t Universe_narrow_oop_shift_address;152uint64_t CodeCache_heap_address;153154/* Volatiles */155uint8_t Use_Compressed_Oops;156uint64_t Universe_narrow_oop_base;157uint32_t Universe_narrow_oop_shift;158uint64_t CodeCache_low;159uint64_t CodeCache_high;160uint64_t CodeCache_segmap_low;161uint64_t CodeCache_segmap_high;162163int32_t SIZE_CodeCache_log2_segment;164165uint64_t methodPtr;166uint64_t bcx;167168Nmethod_t *N; /*Inlined methods support */169Frame_t prev_fr;170Frame_t curr_fr;171};172173static int174read_string(struct ps_prochandle *P,175char *buf, /* caller's buffer */176size_t size, /* upper limit on bytes to read */177uintptr_t addr) /* address in process */178{179int err = PS_OK;180while (size-- > 1 && err == PS_OK) {181err = ps_pread(P, addr, buf, 1);182if (*buf == '\0') {183return PS_OK;184}185addr += 1;186buf += 1;187}188return -1;189}190191static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) {192int err = -1;193uint32_t ptr32;194err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));195*ptr = ptr32;196return err;197}198199static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) {200int err = -1;201uint32_t ptr32;202203switch (DATA_MODEL) {204case PR_MODEL_LP64:205err = ps_pread(J->P, base, ptr, sizeof(uint64_t));206break;207case PR_MODEL_ILP32:208err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));209*ptr = ptr32;210break;211}212213return err;214}215216static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) {217uint64_t ptr;218int err;219char buffer[1024];220221*stringp = NULL;222err = read_pointer(J, base, &ptr);223CHECK_FAIL(err);224if (ptr != 0) {225err = read_string(J->P, buffer, sizeof(buffer), ptr);226CHECK_FAIL(err);227*stringp = strdup(buffer);228}229return PS_OK;230231fail:232return err;233}234235static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) {236uint64_t ptr;237int err;238239err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName);240CHECK_FAIL(err);241err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName);242CHECK_FAIL(err);243err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address);244CHECK_FAIL(err);245246return PS_OK;247248fail:249if (vmp->typeName != NULL) free((void*)vmp->typeName);250if (vmp->fieldName != NULL) free((void*)vmp->fieldName);251return err;252}253254static int parse_vmstructs(jvm_agent_t* J) {255VMStructEntry vmVar;256VMStructEntry* vmp = &vmVar;257uint64_t gHotSpotVMStructs;258psaddr_t sym_addr;259uint64_t base;260int err;261262/* Clear *vmp now in case we jump to fail: */263memset(vmp, 0, sizeof(VMStructEntry));264265err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr);266CHECK_FAIL(err);267err = read_pointer(J, sym_addr, &gHotSpotVMStructs);268CHECK_FAIL(err);269base = gHotSpotVMStructs;270271err = PS_OK;272while (err == PS_OK) {273memset(vmp, 0, sizeof(VMStructEntry));274err = parse_vmstruct_entry(J, base, vmp);275if (err != PS_OK || vmp->typeName == NULL) {276break;277}278279if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {280if (strcmp("_heap", vmp->fieldName) == 0) {281err = read_pointer(J, vmp->address, &J->CodeCache_heap_address);282}283} else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {284if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {285J->Universe_narrow_oop_base_address = vmp->address;286}287if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) {288J->Universe_narrow_oop_shift_address = vmp->address;289}290}291CHECK_FAIL(err);292293base += SIZE_VMStructEntry;294if (vmp->typeName != NULL) free((void*)vmp->typeName);295if (vmp->fieldName != NULL) free((void*)vmp->fieldName);296}297298return PS_OK;299300fail:301if (vmp->typeName != NULL) free((void*)vmp->typeName);302if (vmp->fieldName != NULL) free((void*)vmp->fieldName);303return -1;304}305306static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) {307psaddr_t sym_addr;308int err;309310err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);311if (err != PS_OK) goto fail;312*valuep = sym_addr;313return PS_OK;314315fail:316return err;317}318319static int read_volatiles(jvm_agent_t* J) {320uint64_t ptr;321int err;322323err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);324if (err == PS_OK) {325err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t));326CHECK_FAIL(err);327} else {328J->Use_Compressed_Oops = 0;329}330331err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base);332CHECK_FAIL(err);333err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));334CHECK_FAIL(err);335336err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +337OFFSET_VirtualSpace_low, &J->CodeCache_low);338CHECK_FAIL(err);339err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +340OFFSET_VirtualSpace_high, &J->CodeCache_high);341CHECK_FAIL(err);342err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +343OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low);344CHECK_FAIL(err);345err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +346OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high);347CHECK_FAIL(err);348349err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size,350&J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));351CHECK_FAIL(err);352353return PS_OK;354355fail:356return err;357}358359360static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {361/* make sure the code cache is up to date */362return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high);363}364365static uint64_t segment_for(jvm_agent_t* J, uint64_t p) {366return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment;367}368369static uint64_t block_at(jvm_agent_t* J, int i) {370return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment);371}372373static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {374int err;375376*startp = 0;377if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) {378int32_t used;379uint64_t segment = segment_for(J, ptr);380uint64_t block = J->CodeCache_segmap_low;381uint8_t tag;382err = ps_pread(J->P, block + segment, &tag, sizeof(tag));383CHECK_FAIL(err);384if (tag == 0xff)385return PS_OK;386while (tag > 0) {387err = ps_pread(J->P, block + segment, &tag, sizeof(tag));388CHECK_FAIL(err);389segment -= tag;390}391block = block_at(J, segment);392err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));393CHECK_FAIL(err);394if (used) {395*startp = block + SIZE_HeapBlockHeader;396}397}398return PS_OK;399400fail:401return -1;402}403404static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) {405psaddr_t sym_addr;406int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);407if (err == PS_OK) {408err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t));409return err;410}411*valuep = -1;412return -1;413}414415jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) {416jvm_agent_t* J;417int err;418419if (vers != JVM_DB_VERSION) {420errno = ENOTSUP;421return NULL;422}423424J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1);425426debug = getenv("LIBJVMDB_DEBUG") != NULL;427if (debug) debug = 3;428429if (debug) {430fprintf(stderr, "Jagent_create: debug=%d\n", debug);431#ifdef X86_COMPILER2432fprintf(stderr, "Jagent_create: R_SP=%d, R_FP=%d, POINTER_SIZE=%d\n", R_SP, R_FP, POINTER_SIZE);433#endif /* X86_COMPILER2 */434}435436J->P = P;437438// Initialize the initial previous frame439440J->prev_fr.fp = 0;441J->prev_fr.pc = 0;442J->prev_fr.sp = 0;443J->prev_fr.sender_sp = 0;444445err = find_symbol(J, "__1cHnmethodG__vtbl_", &J->nmethod_vtbl);446CHECK_FAIL(err);447err = find_symbol(J, "__1cKBufferBlobG__vtbl_", &J->BufferBlob_vtbl);448if (err != PS_OK) J->BufferBlob_vtbl = 0;449err = find_symbol(J, "__1cICodeBlobG__vtbl_", &J->CodeBlob_vtbl);450CHECK_FAIL(err);451err = find_symbol(J, "__1cLRuntimeStubG__vtbl_", &J->RuntimeStub_vtbl);452CHECK_FAIL(err);453err = find_symbol(J, "__1cGMethodG__vtbl_", &J->Method_vtbl);454CHECK_FAIL(err);455456err = parse_vmstructs(J);457CHECK_FAIL(err);458err = read_volatiles(J);459CHECK_FAIL(err);460461return J;462463fail:464Jagent_destroy(J);465return NULL;466}467468void Jagent_destroy(jvm_agent_t *J) {469if (J != NULL) {470free(J);471}472}473474static int is_method(jvm_agent_t* J, uint64_t methodPtr) {475uint64_t klass;476int err = read_pointer(J, methodPtr, &klass);477if (err != PS_OK) goto fail;478return klass == J->Method_vtbl;479480fail:481return 0;482}483484static int485name_for_methodPtr(jvm_agent_t* J, uint64_t methodPtr, char * result, size_t size)486{487short nameIndex;488short signatureIndex;489uint64_t constantPool;490uint64_t constMethod;491uint64_t nameSymbol;492uint64_t signatureSymbol;493uint64_t klassPtr;494uint64_t klassSymbol;495short klassSymbolLength;496short nameSymbolLength;497short signatureSymbolLength;498char * nameString = NULL;499char * klassString = NULL;500char * signatureString = NULL;501int err;502503err = read_pointer(J, methodPtr + OFFSET_Method_constMethod, &constMethod);504CHECK_FAIL(err);505err = read_pointer(J, constMethod + OFFSET_ConstMethod_constants, &constantPool);506CHECK_FAIL(err);507508/* To get name string */509err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_name_index, &nameIndex, 2);510CHECK_FAIL(err);511err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_ConstantPool, &nameSymbol);512CHECK_FAIL(err);513// The symbol is a CPSlot and has lower bit set to indicate metadata514nameSymbol &= (~1); // remove metadata lsb515err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2);516CHECK_FAIL(err);517nameString = (char*)calloc(nameSymbolLength + 1, 1);518err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength);519CHECK_FAIL(err);520521/* To get signature string */522err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_signature_index, &signatureIndex, 2);523CHECK_FAIL(err);524err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_ConstantPool, &signatureSymbol);525CHECK_FAIL(err);526signatureSymbol &= (~1); // remove metadata lsb527err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2);528CHECK_FAIL(err);529signatureString = (char*)calloc(signatureSymbolLength + 1, 1);530err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength);531CHECK_FAIL(err);532533/* To get klass string */534err = read_pointer(J, constantPool + OFFSET_ConstantPool_pool_holder, &klassPtr);535CHECK_FAIL(err);536err = read_pointer(J, klassPtr + OFFSET_Klass_name, &klassSymbol);537CHECK_FAIL(err);538err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2);539CHECK_FAIL(err);540klassString = (char*)calloc(klassSymbolLength + 1, 1);541err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength);542CHECK_FAIL(err);543544result[0] = '\0';545if (snprintf(result, size,546"%s.%s%s",547klassString,548nameString,549signatureString) >= size) {550// truncation551goto fail;552}553554if (nameString != NULL) free(nameString);555if (klassString != NULL) free(klassString);556if (signatureString != NULL) free(signatureString);557558return PS_OK;559560fail:561if (debug) {562fprintf(stderr, "name_for_methodPtr: FAIL \n\n");563}564if (nameString != NULL) free(nameString);565if (klassString != NULL) free(klassString);566if (signatureString != NULL) free(signatureString);567return -1;568}569570static int nmethod_info(Nmethod_t *N)571{572jvm_agent_t *J = N->J;573uint64_t nm = N->nm;574int32_t err;575576if (debug > 2 )577fprintf(stderr, "\t nmethod_info: BEGIN \n");578579/* Instructions */580err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32);581CHECK_FAIL(err);582err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32);583CHECK_FAIL(err);584err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32);585CHECK_FAIL(err);586err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32);587CHECK_FAIL(err);588589/* Metadata */590err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32);591CHECK_FAIL(err);592err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->metadata_end, SZ32);593CHECK_FAIL(err);594595/* scopes_pcs */596err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32);597CHECK_FAIL(err);598err = ps_pread(J->P, nm + OFFSET_nmethod_handler_table_offset, &N->scopes_pcs_end, SZ32);599CHECK_FAIL(err);600601/* scopes_data */602err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32);603CHECK_FAIL(err);604605if (debug > 2 ) {606N->scopes_data_end = N->scopes_pcs_beg;607608fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n",609N->instrs_beg, N->instrs_end);610611fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n",612N->deopt_beg);613614fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n",615N->orig_pc_offset);616617fprintf(stderr, "\t nmethod_info: metadata_beg: %#x, metadata_end: %#x\n",618N->metadata_beg, N->metadata_end);619620fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n",621N->scopes_data_beg, N->scopes_data_end);622623fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n",624N->scopes_pcs_beg, N->scopes_pcs_end);625626fprintf(stderr, "\t nmethod_info: END \n\n");627}628return PS_OK;629630fail:631return err;632}633634static int635raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val)636{637int shift = 0;638int value = 0;639uint8_t ch = 0;640int32_t err;641int32_t sum;642// Constants for UNSIGNED5 coding of Pack200643// see compressedStream.hpp644enum {645lg_H = 6,646H = 1<<lg_H,647BitsPerByte = 8,648L = (1<<BitsPerByte)-H,649};650int i;651652err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t));653CHECK_FAIL(err);654if (debug > 2)655fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch);656657sum = ch;658if ( sum >= L ) {659int32_t lg_H_i = lg_H;660// Read maximum of 5 total bytes (we've already read 1).661// See CompressedReadStream::read_int_mb662for ( i = 0; i < 4; i++) {663err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t));664CHECK_FAIL(err);665sum += ch << lg_H_i;666if (ch < L ) {667*val = sum;668return PS_OK;669}670lg_H_i += lg_H;671}672}673*val = sum;674return PS_OK;675676fail:677return err;678}679680static int681read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line)682{683uint8_t next = 0;684int32_t bci_delta;685int32_t line_delta;686int32_t err;687688if (debug > 2)689fprintf(stderr, "\t\t read_pair: BEGIN\n");690691err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t));692CHECK_FAIL(err);693694if (next == 0) {695if (debug > 2)696fprintf(stderr, "\t\t read_pair: END: next == 0\n");697return 1; /* stream terminated */698}699if (next == 0xFF) {700if (debug > 2)701fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n");702703/* Escape character, regular compression used */704705err = raw_read_int(J, buffer, &bci_delta);706CHECK_FAIL(err);707708err = raw_read_int(J, buffer, &line_delta);709CHECK_FAIL(err);710711*bci += bci_delta;712*line += line_delta;713714if (debug > 2) {715fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n",716line_delta, bci_delta);717fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n",718*line, *bci);719}720} else {721/* Single byte compression used */722*bci += next >> 3;723*line += next & 0x7;724if (debug > 2) {725fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n",726next & 0x7, next >> 3);727fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n",728*line, *bci);729}730}731if (debug > 2)732fprintf(stderr, "\t\t read_pair: END\n");733return PS_OK;734735fail:736if (debug)737fprintf(stderr, "\t\t read_pair: FAIL\n");738return err;739}740741static int742line_number_from_bci(jvm_agent_t* J, Vframe_t *vf)743{744uint64_t buffer;745uint16_t code_size;746uint64_t code_end_delta;747uint64_t constMethod;748int8_t access_flags;749int32_t best_bci = 0;750int32_t stream_bci = 0;751int32_t stream_line = 0;752int32_t err;753754if (debug > 2) {755char name[256];756err = name_for_methodPtr(J, vf->method, name, 256);757CHECK_FAIL(err);758fprintf(stderr, "\t line_number_from_bci: BEGIN, method name: %s, targ bci: %d\n",759name, vf->bci);760}761762err = read_pointer(J, vf->method + OFFSET_Method_constMethod, &constMethod);763CHECK_FAIL(err);764765vf->line = 0;766err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_flags, &access_flags, sizeof(int8_t));767CHECK_FAIL(err);768769if (!(access_flags & ConstMethod_has_linenumber_table)) {770if (debug > 2)771fprintf(stderr, "\t line_number_from_bci: END: !HAS_LINE_NUMBER_TABLE \n\n");772return PS_OK;773}774775/* The line numbers are a short array of 2-tuples [start_pc, line_number].776* Not necessarily sorted and not necessarily one-to-one.777*/778779err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_code_size, &code_size, SZ16);780CHECK_FAIL(err);781782/* inlined_table_start() */783code_end_delta = (uint64_t) (access_flags & AccessFlags_NATIVE) ? 2*POINTER_SIZE : 0;784buffer = constMethod + (uint64_t) SIZE_ConstMethod + (uint64_t) code_size + code_end_delta;785786if (debug > 2) {787fprintf(stderr, "\t\t line_number_from_bci: method: %#llx, native: %d\n",788vf->method, (access_flags & AccessFlags_NATIVE));789fprintf(stderr, "\t\t line_number_from_bci: buffer: %#llx, code_size: %d\n",790buffer, (int) code_size);791}792793while (read_pair(J, &buffer, &stream_bci, &stream_line) == 0) {794if (stream_bci == vf->bci) {795/* perfect match */796if (debug > 2)797fprintf(stderr, "\t line_number_from_bci: END: exact line: %ld \n\n", vf->line);798vf->line = stream_line;799return PS_OK;800} else {801/* update best_bci/line */802if (stream_bci < vf->bci && stream_bci >= best_bci) {803best_bci = stream_bci;804vf->line = stream_line;805if (debug > 2) {806fprintf(stderr, "\t line_number_from_bci: best_bci: %ld, best_line: %ld\n",807best_bci, vf->line);808}809}810}811}812if (debug > 2)813fprintf(stderr, "\t line_number_from_bci: END: line: %ld \n\n", vf->line);814return PS_OK;815816fail:817if (debug)818fprintf(stderr, "\t line_number_from_bci: FAIL\n");819return err;820}821822static int823get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc)824{825int32_t pc_offset;826int32_t err;827828err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32);829CHECK_FAIL(err);830831*real_pc = N->nm + N->instrs_beg + pc_offset;832if (debug > 2) {833fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n",834pc_offset, *real_pc);835}836return PS_OK;837838fail:839return err;840}841842/* Finds a PcDesc with real-pc equal to N->pc */843static int pc_desc_at(Nmethod_t *N)844{845uint64_t pc_diff;846int32_t offs;847int32_t err;848849if (debug > 2)850fprintf(stderr, "\t pc_desc_at: BEGIN\n");851852N->vf_cnt = 0;853N->pc_desc = 0;854855for (offs = N->scopes_pcs_beg; offs < N->scopes_pcs_end; offs += SIZE_PcDesc) {856uint64_t pd;857uint64_t best_pc_diff = 16; /* some approximation */858uint64_t real_pc = 0;859860pd = N->nm + offs;861err = get_real_pc(N, pd, &real_pc);862CHECK_FAIL(err);863864pc_diff = real_pc - N->pc;865866/* In general, this fragment should work */867if (pc_diff == 0) {868N->pc_desc = pd;869if (debug) {870fprintf(stderr, "\t pc_desc_at: END: pc_desc: FOUND: %#lx \n\n", pd);871}872return PS_OK;873}874/* This fragment is to be able to find out an appropriate875* pc_desc entry even if pc_desc info is inaccurate.876*/877if (best_pc_diff > pc_diff && pc_diff > 0) {878best_pc_diff = pc_diff;879N->pc_desc = pd;880}881}882if (debug) {883fprintf(stderr, "\t pc_desc_at: END: pc_desc NOT FOUND");884if (pc_diff < 20)885fprintf(stderr, ", best pc_diff: %d\n\n", pc_diff);886else887fprintf(stderr, "\n\n");888}889return PS_OK;890891fail:892return err;893}894895static int896scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf)897{898uint64_t buffer;899int32_t err;900901if (debug > 2) {902fprintf(stderr, "\t\t scope_desc_at: BEGIN \n");903}904905buffer = N->nm + N->scopes_data_beg + decode_offset;906907err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset);908CHECK_FAIL(err);909910err = raw_read_int(N->J, &buffer, &vf->methodIdx);911CHECK_FAIL(err);912913err = raw_read_int(N->J, &buffer, &vf->bci);914CHECK_FAIL(err);915916if (debug > 2) {917fprintf(stderr, "\t\t scope_desc_at: sender_decode_offset: %#x\n",918vf->sender_decode_offset);919fprintf(stderr, "\t\t scope_desc_at: methodIdx: %d\n", vf->methodIdx);920fprintf(stderr, "\t\t scope_desc_at: bci: %d\n", vf->bci);921922fprintf(stderr, "\t\t scope_desc_at: END \n\n");923}924return PS_OK;925926fail:927return err;928}929930static int scopeDesc_chain(Nmethod_t *N) {931int32_t decode_offset = 0;932int32_t err;933934if (debug > 2) {935fprintf(stderr, "\t scopeDesc_chain: BEGIN\n");936}937938err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset,939&decode_offset, SZ32);940CHECK_FAIL(err);941942while (decode_offset > 0) {943Vframe_t *vf = &N->vframes[N->vf_cnt];944945if (debug > 2) {946fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset);947}948949err = scope_desc_at(N, decode_offset, vf);950CHECK_FAIL(err);951952if (vf->methodIdx > ((N->metadata_end - N->metadata_beg) / POINTER_SIZE)) {953fprintf(stderr, "\t scopeDesc_chain: (methodIdx > metadata length) !\n");954return -1;955}956err = read_pointer(N->J, N->nm + N->metadata_beg + (vf->methodIdx-1)*POINTER_SIZE,957&vf->method);958CHECK_FAIL(err);959960if (vf->method) {961N->vf_cnt++;962err = line_number_from_bci(N->J, vf);963CHECK_FAIL(err);964if (debug > 2) {965fprintf(stderr, "\t scopeDesc_chain: method: %#8llx, line: %ld\n",966vf->method, vf->line);967}968}969decode_offset = vf->sender_decode_offset;970}971if (debug > 2) {972fprintf(stderr, "\t scopeDesc_chain: END \n\n");973}974return PS_OK;975976fail:977if (debug) {978fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n");979}980return err;981}982983984static int985name_for_nmethod(jvm_agent_t* J,986uint64_t nm,987uint64_t pc,988uint64_t method,989char *result,990size_t size,991Jframe_t *jframe992) {993Nmethod_t *N;994Vframe_t *vf;995int32_t err;996int deoptimized = 0;997998if (debug) {999fprintf(stderr, "name_for_nmethod: BEGIN: nmethod: %#llx, pc: %#llx\n", nm, pc);1000}1001if (J->N == NULL) {1002J->N = (Nmethod_t *) malloc(sizeof(Nmethod_t));1003}1004memset(J->N, 0, sizeof(Nmethod_t)); /* Initial stat: all values are zeros */1005N = J->N;1006N->J = J;1007N->nm = nm;1008N->pc = pc;1009N->jframe = jframe;10101011err = nmethod_info(N);1012CHECK_FAIL(err);1013if (debug) {1014fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n",1015pc, N->nm + N->deopt_beg);1016}10171018/* check for a deoptimized frame */1019if ( pc == N->nm + N->deopt_beg) {1020uint64_t base;1021if (debug) {1022fprintf(stderr, "name_for_nmethod: found deoptimized frame\n");1023}1024if (J->prev_fr.sender_sp != 0) {1025base = J->prev_fr.sender_sp + N->orig_pc_offset;1026} else {1027base = J->curr_fr.sp + N->orig_pc_offset;1028}1029err = read_pointer(J, base, &N->pc);1030CHECK_FAIL(err);1031if (debug) {1032fprintf(stderr, "name_for_nmethod: found deoptimized frame converting pc from %#8llx to %#8llx\n",1033pc, N->pc);1034}1035deoptimized = 1;1036}10371038err = pc_desc_at(N);1039CHECK_FAIL(err);10401041if (N->pc_desc > 0) {1042jframe->locinf = 1;1043err = scopeDesc_chain(N);1044CHECK_FAIL(err);1045}1046result[0] = COMP_METHOD_SIGN;1047vf = &N->vframes[0];1048if (N->vf_cnt > 0) {1049jframe->vf_cnt = N->vf_cnt;1050jframe->bci = vf->bci;1051jframe->line = vf->line;1052err = name_for_methodPtr(J, N->vframes[0].method, result+1, size-1);1053CHECK_FAIL(err);1054} else {1055err = name_for_methodPtr(J, method, result+1, size-1);1056CHECK_FAIL(err);1057}1058if (deoptimized) {1059strncat(result, " [deoptimized frame]; ", size - strlen(result) - 1);1060} else {1061strncat(result, " [compiled] ", size - strlen(result) - 1);1062}1063if (debug)1064fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n",1065result, N->vf_cnt);1066return PS_OK;10671068fail:1069if (debug)1070fprintf(stderr, "name_for_nmethod: FAIL \n\n");1071return err;1072}10731074int is_bci(intptr_t bcx) {1075switch (DATA_MODEL) {1076case PR_MODEL_LP64:1077return ((uintptr_t) bcx) <= ((uintptr_t) MAX_METHOD_CODE_SIZE) ;1078case PR_MODEL_ILP32:1079default:1080return 0 <= bcx && bcx <= MAX_METHOD_CODE_SIZE;1081}1082}10831084static int1085name_for_imethod(jvm_agent_t* J,1086uint64_t bcx,1087uint64_t method,1088char *result,1089size_t size,1090Jframe_t *jframe1091) {1092uint64_t bci;1093uint64_t constMethod;1094Vframe_t vframe = {0};1095Vframe_t *vf = &vframe;1096int32_t err;10971098err = read_pointer(J, method + OFFSET_Method_constMethod, &constMethod);1099CHECK_FAIL(err);11001101bci = is_bci(bcx) ? bcx : bcx - (constMethod + (uint64_t) SIZE_ConstMethod);11021103if (debug)1104fprintf(stderr, "\t name_for_imethod: BEGIN: method: %#llx\n", method);11051106err = name_for_methodPtr(J, method, result, size);1107CHECK_FAIL(err);1108if (debug)1109fprintf(stderr, "\t name_for_imethod: method name: %s\n", result);11101111if (bci > 0) {1112vf->method = method;1113vf->bci = bci;1114err = line_number_from_bci(J, vf);1115CHECK_FAIL(err);1116}1117jframe->bci = vf->bci;1118jframe->line = vf->line;1119jframe->locinf = 1;11201121if (debug) {1122fprintf(stderr, "\t name_for_imethod: END: bci: %d, line: %d\n\n",1123vf->bci, vf->line);1124}1125return PS_OK;11261127fail:1128if (debug)1129fprintf(stderr, "\t name_for_imethod: FAIL\n");1130return err;1131}11321133static int1134name_for_codecache(jvm_agent_t* J, uint64_t fp, uint64_t pc, char * result,1135size_t size, Jframe_t *jframe, int* is_interpreted)1136{1137uint64_t start;1138uint64_t vtbl;1139int32_t err;1140*is_interpreted = 0;11411142result[0] = '\0';11431144err = find_start(J, pc, &start);1145CHECK_FAIL(err);11461147err = read_pointer(J, start, &vtbl);1148CHECK_FAIL(err);11491150if (vtbl == J->nmethod_vtbl) {1151uint64_t method;11521153err = read_pointer(J, start + OFFSET_nmethod_method, &method);1154CHECK_FAIL(err);11551156if (debug) {1157fprintf(stderr, "name_for_codecache: start: %#8llx, pc: %#8llx, method: %#8llx \n",1158start, pc, method);1159}1160err = name_for_nmethod(J, start, pc, method, result, size, jframe);1161CHECK_FAIL(err);1162} else if (vtbl == J->BufferBlob_vtbl) {1163const char * name;11641165err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name);11661167/*1168* Temporary usage of string "Interpreter".1169* We need some other way to distinguish "StubRoutines"1170* and regular interpreted frames.1171*/1172if (err == PS_OK && strncmp(name, "Interpreter", 11) == 0) {1173*is_interpreted = 1;1174if (is_method(J, J->methodPtr)) {1175return name_for_imethod(J, J->bcx, J->methodPtr, result, size, jframe);1176}1177}11781179if (err == PS_OK) {1180strncpy(result, name, size);1181free((void*)name);1182} else {1183strncpy(result, "<unknown BufferBlob>", size);1184}1185/* return PS_OK; */1186} else {1187const char * name;11881189err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name);1190if (err == PS_OK) {1191strncpy(result, name, size);1192free((void*)name);1193} else {1194strncpy(result, "<unknown CodeBlob>", size);1195WARN1("unknown CodeBlob: vtbl = 0x%x", vtbl);1196}1197}1198result[size-1] = '\0';11991200#ifdef X86_COMPILER21201if (vtbl != J->RuntimeStub_vtbl) {1202uint64_t trial_pc;1203int frame_size;1204err = ps_pread(J->P, start + OFFSET_CodeBlob_frame_size,1205&frame_size, SZ32);1206CHECK_FAIL(err);12071208// frame_size is in words, we want bytes.1209frame_size *= POINTER_SIZE; /* word => byte conversion */12101211/*1212Because c2 doesn't use FP as a framepointer the value of sp/fp we receive1213in the initial entry to a set of stack frames containing server frames1214will pretty much be nonsense. We can detect that nonsense by looking to1215see if the PC we received is correct if we look at the expected storage1216location in relation to the FP (ie. POINTER_SIZE(FP) )1217*/12181219err = read_pointer(J, fp + POINTER_SIZE , &trial_pc);1220if ( (err != PS_OK || trial_pc != pc) && frame_size > 0 ) {1221// Either we couldn't even read at the "fp" or the pc didn't match1222// both are sure clues that the fp is bogus. We no search the stack1223// for a reasonable number of words trying to find the bogus fp1224// and the current pc in adjacent words. The we will be able to1225// deduce an approximation of the frame pointer and actually get1226// the correct stack pointer. Which we can then unwind for the1227// next frame.1228int i;1229uint64_t check;1230uint64_t base = J->curr_fr.sp;1231uint64_t prev_fp = 0;1232for ( i = 0; i < frame_size * 5 ; i++, base += POINTER_SIZE ) {1233err = read_pointer(J, base , &check);1234CHECK_FAIL(err);1235if (check == fp) {1236base += POINTER_SIZE;1237err = read_pointer(J, base , &check);1238CHECK_FAIL(err);1239if (check == pc) {1240if (debug) {1241fprintf(stderr, "name_for_codecache: found matching fp/pc combo at 0x%llx\n", base - POINTER_SIZE);1242}1243prev_fp = base - 2 * POINTER_SIZE;1244break;1245}1246}1247}1248if ( prev_fp != 0 ) {1249// real_sp is the sp we should have received for this frame1250uint64_t real_sp = prev_fp + 2 * POINTER_SIZE;1251// +POINTER_SIZE because callee owns the return address so caller's sp is +1 word1252jframe->new_sp = real_sp + frame_size + POINTER_SIZE;1253err = read_pointer(J, jframe->new_sp - POINTER_SIZE , &jframe->new_pc);1254CHECK_FAIL(err);1255err = read_pointer(J, jframe->new_sp - 2*POINTER_SIZE, &jframe->new_fp);1256CHECK_FAIL(err);1257return PS_OK;1258}1259}12601261/* A prototype to workaround FP absence */1262/*1263* frame_size can be 0 for StubRoutines (1) frame.1264* In this case it should work with fp as usual.1265*/1266if (frame_size > 0) {1267jframe->new_fp = J->prev_fr.fp + frame_size;1268jframe->new_sp = jframe->new_fp + 2 * POINTER_SIZE;1269} else {1270memset(&J->curr_fr, 0, sizeof(Frame_t));1271err = read_pointer(J, fp, &jframe->new_fp);1272CHECK_FAIL(err);12731274err = read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc);1275CHECK_FAIL(err);1276}1277if (debug) {1278fprintf(stderr, "name_for_codecache: %s, frame_size=%#lx\n",1279result, frame_size);1280fprintf(stderr, "name_for_codecache: prev_fr.fp=%#lx, fp=%#lx\n",1281J->prev_fr.fp, jframe->new_fp);1282}1283}1284#endif /* X86_COMPILER2 */12851286return PS_OK;12871288fail:1289return err;1290}12911292int Jget_vframe(jvm_agent_t* J, int vframe_no,1293char *name, size_t size, Jframe_t *jframe)1294{1295Nmethod_t *N = J->N;1296Vframe_t *vf;1297int32_t err;12981299if (vframe_no >= N->vf_cnt) {1300(void) sprintf(name, "Wrong inlinedMethod%1d()", vframe_no);1301return -1;1302}1303vf = N->vframes + vframe_no;1304name[0] = COMP_METHOD_SIGN;1305err = name_for_methodPtr(J, vf->method, name + 1, size);1306CHECK_FAIL(err);13071308jframe->bci = vf->bci;1309jframe->line = vf->line;1310if (debug) {1311fprintf(stderr, "\t Jget_vframe: method name: %s, line: %ld\n",1312name, vf->line);1313}1314return PS_OK;13151316fail:1317if (debug) {1318fprintf(stderr, "\t Jget_vframe: FAIL\n");1319}1320return err;1321}13221323#define MAX_SYM_SIZE 25613241325int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,1326size_t size, Jframe_t *jframe) {1327uintptr_t fp;1328uintptr_t pc;1329/* arguments given to read_pointer need to be worst case sized */1330uint64_t methodPtr = 0;1331uint64_t sender_sp;1332uint64_t bcx = 0;1333int is_interpreted = 0;1334int result = PS_OK;1335int err = PS_OK;13361337if (J == NULL) {1338return -1;1339}13401341jframe->vf_cnt = 1;1342jframe->new_fp = 0;1343jframe->new_pc = 0;1344jframe->line = 0;1345jframe->bci = 0;1346jframe->locinf = 0;13471348read_volatiles(J);1349pc = (uintptr_t) regs[R_PC];1350J->curr_fr.pc = pc;1351J->curr_fr.fp = regs[R_FP];1352J->curr_fr.sp = regs[R_SP];13531354if (debug)1355fprintf(stderr, "Jlookup_by_regs: BEGINs: fp=%#lx, pc=%#lx\n", regs[R_FP], pc);13561357#if defined(sparc) || defined(__sparc)1358/* The following workaround is for SPARC. CALL instruction occupates 8 bytes.1359* In the pcDesc structure return pc offset is recorded for CALL instructions.1360* regs[R_PC] contains a CALL instruction pc offset.1361*/1362pc += 8;1363bcx = (uintptr_t) regs[R_L1];1364methodPtr = (uintptr_t) regs[R_L2];1365sender_sp = regs[R_I5];1366if (debug > 2) {1367fprintf(stderr, "\nregs[R_I1]=%lx, regs[R_I2]=%lx, regs[R_I5]=%lx, regs[R_L1]=%lx, regs[R_L2]=%lx\n",1368regs[R_I1], regs[R_I2], regs[R_I5], regs[R_L1], regs[R_L2]);1369}1370#elif defined(i386) || defined(__i386) || defined(__amd64)13711372fp = (uintptr_t) regs[R_FP];1373if (J->prev_fr.fp == 0) {1374#ifdef X86_COMPILER21375/* A workaround for top java frames */1376J->prev_fr.fp = (uintptr_t)(regs[R_SP] - 2 * POINTER_SIZE);1377#else1378J->prev_fr.fp = (uintptr_t)(regs[R_SP] - POINTER_SIZE);1379#endif /* COMPILER2 */1380}1381if (debug > 2) {1382printf("Jlookup_by_regs: J->prev_fr.fp = %#lx\n", J->prev_fr.fp);1383}13841385if (read_pointer(J, fp + OFFSET_interpreter_frame_method, &methodPtr) != PS_OK) {1386methodPtr = 0;1387}1388if (read_pointer(J, fp + OFFSET_interpreter_frame_sender_sp, &sender_sp) != PS_OK) {1389sender_sp = 0;1390}1391if (read_pointer(J, fp + OFFSET_interpreter_frame_bcx_offset, &bcx) != PS_OK) {1392bcx = 0;1393}1394#endif /* i386 */13951396J->methodPtr = methodPtr;1397J->bcx = bcx;13981399/* On x86 with C2 JVM: native frame may have wrong regs[R_FP]1400* For example: JVM_SuspendThread frame poins to the top interpreted frame.1401* If we call is_method(J, methodPtr) before codecache_contains(J, pc)1402* then we go over and omit both: nmethod and I2CAdapter frames.1403* Note, that regs[R_PC] is always correct if frame defined correctly.1404* So it is better to call codecache_contains(J, pc) from the beginning.1405*/1406#ifndef X86_COMPILER21407if (is_method(J, J->methodPtr)) {1408result = name_for_imethod(J, bcx, J->methodPtr, name, size, jframe);1409/* If the methodPtr is a method then this is highly likely to be1410an interpreter frame */1411if (result >= 0) {1412is_interpreted = 1;1413}1414} else1415#endif /* ! X86_COMPILER2 */14161417if (codecache_contains(J, pc)) {1418result = name_for_codecache(J, fp, pc, name, size, jframe, &is_interpreted);1419}1420#ifdef X86_COMPILER21421else if (is_method(J, J->methodPtr)) {1422result = name_for_imethod(J, bcx, J->methodPtr, name, size, jframe);1423/* If the methodPtr is a method then this is highly likely to be1424an interpreter frame */1425if (result >= 0) {1426is_interpreted = 1;1427}1428}1429#endif /* X86_COMPILER2 */1430else {1431if (debug) {1432fprintf(stderr, "Jlookup_by_regs: END with -1\n\n");1433}1434result = -1;1435}1436if (!is_interpreted) {1437sender_sp = 0;1438}1439J->curr_fr.sender_sp = sender_sp;14401441#ifdef X86_COMPILER21442if (!J->curr_fr.fp) {1443J->curr_fr.fp = (jframe->new_fp) ? jframe->new_fp : (uintptr_t)regs[R_FP];1444}1445if (!jframe->new_pc && jframe->new_fp) {1446// This seems dubious1447read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc);1448CHECK_FAIL(err);1449if (debug > 2) {1450printf("Jlookup_by_regs: (update pc) jframe->new_fp: %#llx, jframe->new_pc: %#llx\n",1451jframe->new_fp, jframe->new_pc);1452}1453}14541455#endif /* X86_COMPILER2 */1456J->prev_fr = J->curr_fr;14571458if (debug)1459fprintf(stderr, "Jlookup_by_regs: END\n\n");14601461return result;14621463fail:1464return err;1465}14661467void update_gregs(prgregset_t gregs, Jframe_t jframe) {1468#ifdef X86_COMPILER21469if (debug > 0) {1470fprintf(stderr, "update_gregs: before update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);1471}1472/*1473* A workaround for java C2 frames with unconventional FP.1474* may have to modify regset with new values for FP/PC/SP when needed.1475*/1476if (jframe.new_sp) {1477*((uintptr_t *) &gregs[R_SP]) = (uintptr_t) jframe.new_sp;1478} else {1479// *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) gregs[R_FP] + 2 * POINTER_SIZE;1480}14811482if (jframe.new_fp) {1483*((uintptr_t *) &gregs[R_FP]) = (uintptr_t) jframe.new_fp;1484}1485if (jframe.new_pc) {1486*((uintptr_t *) &gregs[R_PC]) = (uintptr_t) jframe.new_pc;1487}1488if (debug > 0) {1489fprintf(stderr, "update_gregs: after update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);1490}1491#endif /* X86_COMPILER2 */1492}14931494/*1495* Iterates over java frames at current location given by 'gregs'.1496*1497* Returns -1 if no java frames are present or if an error is encountered.1498* Returns the result of calling 'func' if the return value is non-zero.1499* Returns 0 otherwise.1500*/1501int Jframe_iter(jvm_agent_t *J, prgregset_t gregs, java_stack_f *func, void* cld) {1502char buf[MAX_SYM_SIZE + 1];1503Jframe_t jframe;1504int i = 0, res;1505#ifdef X86_COMPILER21506if (debug > 0) {1507fprintf(stderr, "Jframe_iter: Entry sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);1508}1509#endif /* X86_COMPILER2 */15101511memset(&jframe, 0, sizeof(Jframe_t));1512memset(buf, 0, sizeof(buf));1513res = Jlookup_by_regs(J, gregs, buf, sizeof(buf), &jframe);1514if (res != PS_OK)1515return (-1);151615171518res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1,1519jframe.line, NULL);1520if (res != 0) {1521update_gregs(gregs, jframe);1522return (res);1523}1524for (i = 1; i < jframe.vf_cnt; i++) {1525Jget_vframe(J, i, buf, sizeof(buf), &jframe);1526res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1,1527jframe.line, NULL);1528if (res != 0) {1529update_gregs(gregs, jframe);1530return (res);1531}1532}1533update_gregs(gregs, jframe);1534return (0);1535}153615371538