|
Java example source code file (libjvm_db.c)
The libjvm_db.c Java example source code
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <gelf.h>
#include "libjvm_db.h"
#include "JvmOffsets.h"
#define LIBJVM_SO "libjvm.so"
#if defined(i386) || defined(__i386) || defined(__amd64)
#ifdef COMPILER2
#define X86_COMPILER2
#endif /* COMPILER2 */
#endif /* i386 */
typedef struct {
short vf_cnt; /* number of recognized java vframes */
short bci; /* current frame method byte code index */
int line; /* current frame method source line */
uint64_t new_fp; /* fp for the next frame */
uint64_t new_pc; /* pc for the next frame */
uint64_t new_sp; /* "raw" sp for the next frame (includes extension by interpreter/adapter */
char locinf; /* indicates there is valid location info */
} Jframe_t;
int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,
size_t size, Jframe_t *jframe);
int main(int arg) { return arg; }
static int debug = 0;
static void failed(int err, const char * file, int line) {
if (debug) {
fprintf(stderr, "failed %d at %s:%d\n", err, file, line);
}
}
static void warn(const char * file, int line, const char * msg) {
if (debug) {
fprintf(stderr, "warning: %s at %s:%d\n", msg, file, line);
}
}
static void warn1(const char * file, int line, const char * msg, intptr_t arg1) {
if (debug) {
fprintf(stderr, "warning: ");
fprintf(stderr, msg, arg1);
fprintf(stderr, " at %s:%d\n", file, line);
}
}
#define CHECK_FAIL(err) \
if (err != PS_OK) { failed(err, __FILE__, __LINE__); goto fail; }
#define WARN(msg) warn(__FILE__, __LINE__, msg)
#define WARN1(msg, arg1) warn1(__FILE__, __LINE__, msg, arg1)
typedef struct VMStructEntry {
const char * typeName; /* The type name containing the given field (example: "Klass") */
const char * fieldName; /* The field name within the type (example: "_name") */
uint64_t address; /* Address of field; only used for static fields */
/* ("offset" can not be reused because of apparent SparcWorks compiler bug */
/* in generation of initializer data) */
} VMStructEntry;
/* Prototyping inlined methods */
int sprintf(char *s, const char *format, ...);
#define SZ16 sizeof(int16_t)
#define SZ32 sizeof(int32_t)
#define COMP_METHOD_SIGN '*'
#define MAX_VFRAMES_CNT 256
typedef struct vframe {
uint64_t method;
int32_t sender_decode_offset;
int32_t methodIdx;
int32_t bci;
int32_t line;
} Vframe_t;
typedef struct frame {
uintptr_t fp;
uintptr_t pc;
uintptr_t sp;
uintptr_t sender_sp; // The unextended sp of the caller
} Frame_t;
typedef struct Nmethod_t {
struct jvm_agent* J;
Jframe_t *jframe;
uint64_t nm; /* _nmethod */
uint64_t pc;
uint64_t pc_desc;
int32_t orig_pc_offset; /* _orig_pc_offset */
int32_t instrs_beg; /* _code_offset */
int32_t instrs_end;
int32_t deopt_beg; /* _deoptimize_offset */
int32_t scopes_data_beg; /* _scopes_data_offset */
int32_t scopes_data_end;
int32_t metadata_beg; /* _metadata_offset */
int32_t metadata_end;
int32_t scopes_pcs_beg; /* _scopes_pcs_offset */
int32_t scopes_pcs_end;
int vf_cnt;
Vframe_t vframes[MAX_VFRAMES_CNT];
} Nmethod_t;
struct jvm_agent {
struct ps_prochandle* P;
uint64_t nmethod_vtbl;
uint64_t CodeBlob_vtbl;
uint64_t BufferBlob_vtbl;
uint64_t RuntimeStub_vtbl;
uint64_t Method_vtbl;
uint64_t Use_Compressed_Oops_address;
uint64_t Universe_narrow_oop_base_address;
uint64_t Universe_narrow_oop_shift_address;
uint64_t CodeCache_heap_address;
/* Volatiles */
uint8_t Use_Compressed_Oops;
uint64_t Universe_narrow_oop_base;
uint32_t Universe_narrow_oop_shift;
uint64_t CodeCache_low;
uint64_t CodeCache_high;
uint64_t CodeCache_segmap_low;
uint64_t CodeCache_segmap_high;
int32_t SIZE_CodeCache_log2_segment;
uint64_t methodPtr;
uint64_t bcx;
Nmethod_t *N; /*Inlined methods support */
Frame_t prev_fr;
Frame_t curr_fr;
};
static int
read_string(struct ps_prochandle *P,
char *buf, /* caller's buffer */
size_t size, /* upper limit on bytes to read */
uintptr_t addr) /* address in process */
{
int err = PS_OK;
while (size-- > 1 && err == PS_OK) {
err = ps_pread(P, addr, buf, 1);
if (*buf == '\0') {
return PS_OK;
}
addr += 1;
buf += 1;
}
return -1;
}
static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) {
int err = -1;
uint32_t ptr32;
err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));
*ptr = ptr32;
return err;
}
static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) {
int err = -1;
uint32_t ptr32;
switch (DATA_MODEL) {
case PR_MODEL_LP64:
err = ps_pread(J->P, base, ptr, sizeof(uint64_t));
break;
case PR_MODEL_ILP32:
err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));
*ptr = ptr32;
break;
}
return err;
}
static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) {
uint64_t ptr;
int err;
char buffer[1024];
*stringp = NULL;
err = read_pointer(J, base, &ptr);
CHECK_FAIL(err);
if (ptr != 0) {
err = read_string(J->P, buffer, sizeof(buffer), ptr);
CHECK_FAIL(err);
*stringp = strdup(buffer);
}
return PS_OK;
fail:
return err;
}
static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) {
uint64_t ptr;
int err;
err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName);
CHECK_FAIL(err);
err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName);
CHECK_FAIL(err);
err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address);
CHECK_FAIL(err);
return PS_OK;
fail:
if (vmp->typeName != NULL) free((void*)vmp->typeName);
if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
return err;
}
static int parse_vmstructs(jvm_agent_t* J) {
VMStructEntry vmVar;
VMStructEntry* vmp = &vmVar;
uint64_t gHotSpotVMStructs;
psaddr_t sym_addr;
uint64_t base;
int err;
err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr);
CHECK_FAIL(err);
err = read_pointer(J, sym_addr, &gHotSpotVMStructs);
CHECK_FAIL(err);
base = gHotSpotVMStructs;
err = PS_OK;
while (err == PS_OK) {
memset(vmp, 0, sizeof(VMStructEntry));
err = parse_vmstruct_entry(J, base, vmp);
if (err != PS_OK || vmp->typeName == NULL) {
break;
}
if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {
if (strcmp("_heap", vmp->fieldName) == 0) {
err = read_pointer(J, vmp->address, &J->CodeCache_heap_address);
}
} else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {
if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
J->Universe_narrow_oop_base_address = vmp->address;
}
if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) {
J->Universe_narrow_oop_shift_address = vmp->address;
}
}
CHECK_FAIL(err);
base += SIZE_VMStructEntry;
if (vmp->typeName != NULL) free((void*)vmp->typeName);
if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
}
return PS_OK;
fail:
if (vmp->typeName != NULL) free((void*)vmp->typeName);
if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
return -1;
}
static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) {
psaddr_t sym_addr;
int err;
err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);
if (err != PS_OK) goto fail;
*valuep = sym_addr;
return PS_OK;
fail:
return err;
}
static int read_volatiles(jvm_agent_t* J) {
uint64_t ptr;
int err;
err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
if (err == PS_OK) {
err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t));
CHECK_FAIL(err);
} else {
J->Use_Compressed_Oops = 0;
}
err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base);
CHECK_FAIL(err);
err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
CHECK_FAIL(err);
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +
OFFSET_VirtualSpace_low, &J->CodeCache_low);
CHECK_FAIL(err);
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory +
OFFSET_VirtualSpace_high, &J->CodeCache_high);
CHECK_FAIL(err);
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +
OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low);
CHECK_FAIL(err);
err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap +
OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high);
CHECK_FAIL(err);
err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size,
&J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));
CHECK_FAIL(err);
return PS_OK;
fail:
return err;
}
static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {
/* make sure the code cache is up to date */
return (J->CodeCache_low <= ptr && ptr < J->CodeCache_high);
}
static uint64_t segment_for(jvm_agent_t* J, uint64_t p) {
return (p - J->CodeCache_low) >> J->SIZE_CodeCache_log2_segment;
}
static uint64_t block_at(jvm_agent_t* J, int i) {
return J->CodeCache_low + (i << J->SIZE_CodeCache_log2_segment);
}
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
int err;
*startp = 0;
if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) {
int32_t used;
uint64_t segment = segment_for(J, ptr);
uint64_t block = J->CodeCache_segmap_low;
uint8_t tag;
err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
CHECK_FAIL(err);
if (tag == 0xff)
return PS_OK;
while (tag > 0) {
err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
CHECK_FAIL(err);
segment -= tag;
}
block = block_at(J, segment);
err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));
CHECK_FAIL(err);
if (used) {
*startp = block + SIZE_HeapBlockHeader;
}
}
return PS_OK;
fail:
return -1;
}
static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) {
psaddr_t sym_addr;
int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);
if (err == PS_OK) {
err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t));
return err;
}
*valuep = -1;
return -1;
}
jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) {
jvm_agent_t* J;
int err;
if (vers != JVM_DB_VERSION) {
errno = ENOTSUP;
return NULL;
}
J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1);
debug = getenv("LIBJVMDB_DEBUG") != NULL;
if (debug) debug = 3;
if (debug) {
fprintf(stderr, "Jagent_create: debug=%d\n", debug);
#ifdef X86_COMPILER2
fprintf(stderr, "Jagent_create: R_SP=%d, R_FP=%d, POINTER_SIZE=%d\n", R_SP, R_FP, POINTER_SIZE);
#endif /* X86_COMPILER2 */
}
J->P = P;
// Initialize the initial previous frame
J->prev_fr.fp = 0;
J->prev_fr.pc = 0;
J->prev_fr.sp = 0;
J->prev_fr.sender_sp = 0;
err = find_symbol(J, "__1cHnmethodG__vtbl_", &J->nmethod_vtbl);
CHECK_FAIL(err);
err = find_symbol(J, "__1cKBufferBlobG__vtbl_", &J->BufferBlob_vtbl);
if (err != PS_OK) J->BufferBlob_vtbl = 0;
err = find_symbol(J, "__1cICodeBlobG__vtbl_", &J->CodeBlob_vtbl);
CHECK_FAIL(err);
err = find_symbol(J, "__1cLRuntimeStubG__vtbl_", &J->RuntimeStub_vtbl);
CHECK_FAIL(err);
err = find_symbol(J, "__1cGMethodG__vtbl_", &J->Method_vtbl);
CHECK_FAIL(err);
err = parse_vmstructs(J);
CHECK_FAIL(err);
err = read_volatiles(J);
CHECK_FAIL(err);
return J;
fail:
Jagent_destroy(J);
return NULL;
}
void Jagent_destroy(jvm_agent_t *J) {
if (J != NULL) {
free(J);
}
}
static int is_method(jvm_agent_t* J, uint64_t methodPtr) {
uint64_t klass;
int err = read_pointer(J, methodPtr, &klass);
if (err != PS_OK) goto fail;
return klass == J->Method_vtbl;
fail:
return 0;
}
static int
name_for_methodPtr(jvm_agent_t* J, uint64_t methodPtr, char * result, size_t size)
{
short nameIndex;
short signatureIndex;
uint64_t constantPool;
uint64_t constMethod;
uint64_t nameSymbol;
uint64_t signatureSymbol;
uint64_t klassPtr;
uint64_t klassSymbol;
short klassSymbolLength;
short nameSymbolLength;
short signatureSymbolLength;
char * nameString = NULL;
char * klassString = NULL;
char * signatureString = NULL;
int err;
err = read_pointer(J, methodPtr + OFFSET_Method_constMethod, &constMethod);
CHECK_FAIL(err);
err = read_pointer(J, constMethod + OFFSET_ConstMethod_constants, &constantPool);
CHECK_FAIL(err);
/* To get name string */
err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_name_index, &nameIndex, 2);
CHECK_FAIL(err);
err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_ConstantPool, &nameSymbol);
CHECK_FAIL(err);
// The symbol is a CPSlot and has lower bit set to indicate metadata
nameSymbol &= (~1); // remove metadata lsb
err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2);
CHECK_FAIL(err);
nameString = (char*)calloc(nameSymbolLength + 1, 1);
err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength);
CHECK_FAIL(err);
/* To get signature string */
err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_signature_index, &signatureIndex, 2);
CHECK_FAIL(err);
err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_ConstantPool, &signatureSymbol);
CHECK_FAIL(err);
signatureSymbol &= (~1); // remove metadata lsb
err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2);
CHECK_FAIL(err);
signatureString = (char*)calloc(signatureSymbolLength + 1, 1);
err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength);
CHECK_FAIL(err);
/* To get klass string */
err = read_pointer(J, constantPool + OFFSET_ConstantPool_pool_holder, &klassPtr);
CHECK_FAIL(err);
err = read_pointer(J, klassPtr + OFFSET_Klass_name, &klassSymbol);
CHECK_FAIL(err);
err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2);
CHECK_FAIL(err);
klassString = (char*)calloc(klassSymbolLength + 1, 1);
err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength);
CHECK_FAIL(err);
result[0] = '\0';
strncat(result, klassString, size);
size -= strlen(klassString);
strncat(result, ".", size);
size -= 1;
strncat(result, nameString, size);
size -= strlen(nameString);
strncat(result, signatureString, size);
if (nameString != NULL) free(nameString);
if (klassString != NULL) free(klassString);
if (signatureString != NULL) free(signatureString);
return PS_OK;
fail:
if (debug) {
fprintf(stderr, "name_for_methodPtr: FAIL \n\n");
}
if (nameString != NULL) free(nameString);
if (klassString != NULL) free(klassString);
if (signatureString != NULL) free(signatureString);
return -1;
}
static int nmethod_info(Nmethod_t *N)
{
jvm_agent_t *J = N->J;
uint64_t nm = N->nm;
int32_t err;
if (debug > 2 )
fprintf(stderr, "\t nmethod_info: BEGIN \n");
/* Instructions */
err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32);
CHECK_FAIL(err);
/* Metadata */
err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->metadata_end, SZ32);
CHECK_FAIL(err);
/* scopes_pcs */
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32);
CHECK_FAIL(err);
err = ps_pread(J->P, nm + OFFSET_nmethod_handler_table_offset, &N->scopes_pcs_end, SZ32);
CHECK_FAIL(err);
/* scopes_data */
err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32);
CHECK_FAIL(err);
if (debug > 2 ) {
N->scopes_data_end = N->scopes_pcs_beg;
fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n",
N->instrs_beg, N->instrs_end);
fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n",
N->deopt_beg);
fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n",
N->orig_pc_offset);
fprintf(stderr, "\t nmethod_info: metadata_beg: %#x, metadata_end: %#x\n",
N->metadata_beg, N->metadata_end);
fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n",
N->scopes_data_beg, N->scopes_data_end);
fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n",
N->scopes_pcs_beg, N->scopes_pcs_end);
fprintf(stderr, "\t nmethod_info: END \n\n");
}
return PS_OK;
fail:
return err;
}
static int
raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val)
{
int shift = 0;
int value = 0;
uint8_t ch = 0;
int32_t err;
int32_t sum;
// Constants for UNSIGNED5 coding of Pack200
// see compressedStream.hpp
enum {
lg_H = 6,
H = 1<
Other Java examples (source code examples)Here is a short list of links related to this Java libjvm_db.c source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.