Skip to content
Draft

v0 #338

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ddprof-lib/src/main/cpp/stackWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "stackFrame.h"
#include "symbols.h"
#include "vmStructs.h"
#include "vmStructs_dd.h"


const uintptr_t SAME_STACK_DISTANCE = 8192;
Expand Down Expand Up @@ -370,6 +371,8 @@ __attribute__((no_sanitize("address"))) int StackWalker::walkVM(void* ucontext,

if (is_plausible_interpreter_frame) {
VMMethod* method = ((VMMethod**)fp)[InterpreterFrame::method_offset];
// assert(ddprof::BootstrapClassLoader::loaded_by(method));

jmethodID method_id = getMethodId(method);
if (method_id != NULL) {
const char* bytecode_start = method->bytecode();
Expand All @@ -386,6 +389,7 @@ __attribute__((no_sanitize("address"))) int StackWalker::walkVM(void* ucontext,

if (depth == 0) {
VMMethod* method = (VMMethod*)frame.method();
// assert(ddprof::BootstrapClassLoader::loaded_by(method));
jmethodID method_id = getMethodId(method);
if (method_id != NULL) {
fillFrame(frames[depth++], FRAME_INTERPRETED, 0, method_id);
Expand Down
10 changes: 10 additions & 0 deletions ddprof-lib/src/main/cpp/vmStructs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,16 @@ jmethodID VMMethod::id() {
return NULL;
}

VMKlass* VMMethod::method_holder() {
// We may find a bogus NMethod during stack walking, it does not always point to a valid VMMethod
const char* const_method = (const char*) SafeAccess::load((void**) at(_method_constmethod_offset));
assert(goodPtr(const_method));
const char* cpool = (const char*) SafeAccess::load((void**)(const_method + _constmethod_constants_offset));
assert(goodPtr(cpool));
return *(VMKlass**)(cpool + _pool_holder_offset);
}


jmethodID VMMethod::validatedId() {
jmethodID method_id = id();
if (!_can_dereference_jmethod_id || (goodPtr(method_id) && *(VMMethod**)method_id == this)) {
Expand Down
2 changes: 2 additions & 0 deletions ddprof-lib/src/main/cpp/vmStructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ class VMMethod : VMStructs {
NMethod* code() {
return *(NMethod**) at(_method_code_offset);
}

VMKlass* method_holder();
};

class NMethod : VMStructs {
Expand Down
10 changes: 9 additions & 1 deletion ddprof-lib/src/main/cpp/vmStructs_dd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace ddprof {
VMStructs_::MemoryUsageFunc VMStructs_::_memory_usage_func = NULL;
VMStructs_::GCHeapSummaryFunc VMStructs_::_gc_heap_summary_func = NULL;
VMStructs_::IsValidMethodFunc VMStructs_::_is_valid_method_func = NULL;
VMKlass** BootstrapClassLoader::_object_klass_addr = nullptr;


// Run at agent load time
Expand Down Expand Up @@ -66,6 +67,13 @@ namespace ddprof {
break;
}

if (strcmp(type, "vmClasses") == 0) {
// java/lang/Object must be loaded by bootstrap class loader, we use it to locate
// its CLD
if (strcmp(field, "_klasses[static_cast<int>(vmClassID::Object_klass_knum)]") == 0) {
BootstrapClassLoader::set_object_klass_location(*(::VMKlass***)(entry + address_offset));
}
}
if (strcmp(type, "OSThread") == 0) {
if (strcmp(field, "_state") == 0) {
TEST_LOG("Setting _osthread_state_offset value");
Expand Down Expand Up @@ -395,4 +403,4 @@ namespace ddprof {
jvmti->Deallocate((unsigned char *)method_sig);
jvmti->Deallocate((unsigned char *)method_name);
}
}
}
28 changes: 27 additions & 1 deletion ddprof-lib/src/main/cpp/vmStructs_dd.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ namespace ddprof {
// Copied from JDK's globalDefinitions.hpp 'JavaThreadState' enum
enum JVMJavaThreadState {
_thread_uninitialized = 0, // should never happen (missing initialization)
_thread_new = 2, // just starting up, i.e., in process of being initialized
_thread_new_trans = 3, // corresponding transition state (not used, included for completeness)
_thread_in_native = 4, // running in native code
_thread_in_native_trans = 5, // corresponding transition state
Expand Down Expand Up @@ -189,6 +188,33 @@ namespace ddprof {
}
};

// Bootstrape class loader is immortal. Therefore, classes/methods
// that are loaded by it, are safe to walk.
class BootstrapClassLoader : public ::VMStructs {
private:
// java.lang.Object must be loaded by bootstrap class loader.
// _object_klass points to java/lang/Object instanceKlass stored in vmClasses,
// and we use it to figure out if classes/methods are loaded by bootstrap classloader
static ::VMKlass** _object_klass_addr;

public:
static void set_object_klass_location(::VMKlass** addr) {
_object_klass_addr = addr;
}

// If a Method is loaded by BootstrapClassLoader
static bool loaded_by(::VMMethod* method) {
return loaded_by(method->method_holder());
}

static bool loaded_by(::VMKlass* klass) {
VMKlass* object_klass = *_object_klass_addr;
assert(object_klass != nullptr);
assert(klass != nullptr);
return object_klass->classLoaderData() == klass->classLoaderData();
}
};

class JVMFlag : public VMStructs {
private:
enum {
Expand Down
Loading