...
 
Commits (9)
......@@ -223,7 +223,7 @@ final class ConnectionHandler implements Runnable {
if (sendBuffer.remaining () < responseLength) {
sendBuffer = __expandBuffer (sendBuffer, responseLength);
__log.debug ("expanded send buffer to %d bytes", sendBuffer.capacity ());
__log.trace ("expanded send buffer to %d bytes", sendBuffer.capacity ());
}
if (responseLength > 0) {
......
......@@ -4,6 +4,7 @@ import ch.usi.dag.disl.DiSL;
import ch.usi.dag.disl.DiSL.CodeOption;
import ch.usi.dag.disl.DiSLException;
import ch.usi.dag.disl.JavaNames;
import ch.usi.dag.dislserver.Protocol.ClassInfo;
import ch.usi.dag.dislserver.Protocol.InstrumentClassRequest;
import ch.usi.dag.dislserver.Protocol.InstrumentClassResponse;
import ch.usi.dag.util.Strings;
......@@ -46,14 +47,16 @@ final class RequestProcessor {
public InstrumentClassResponse process (final InstrumentClassRequest request) {
final byte [] classBytes = request.getClassBytes ().toByteArray ();
final String className = __getClassName (request.getClassNameBytes ().toByteArray (), classBytes);
final ClassInfo classInfo = request.getClassInfo ();
final String className = __getClassName (classInfo.getClassName (), classBytes);
final Set <CodeOption> options = CodeOption.setOf (request.getFlags ());
if (__log.traceIsLoggable ()) {
__log.trace (
"instrumenting class %s [%d bytes, %s]",
if (__log.debugIsLoggable ()) {
__log.debug (
"processing class %s of classloader %d [%d bytes, %s]",
className.isEmpty () ? "<unknown>" : className,
classBytes.length, Strings.join ("+", options)
classInfo.getClassLoaderTag (), classBytes.length,
Strings.join ("+", options)
);
}
......@@ -112,21 +115,18 @@ final class RequestProcessor {
private static String __getClassName (
final byte [] nameBytes, final byte [] classBytes
final String name, final byte [] classBytes
) {
String result = Strings.EMPTY_STRING;
if (nameBytes.length > 0) {
result = new String (nameBytes);
}
if (result.isEmpty ()) {
result = JavaNames.getClassNameFromBytes (classBytes);
if (!name.isEmpty ()) {
return name;
} else {
String result = JavaNames.getClassNameFromBytes (classBytes);
if (result == null || result.isEmpty ()) {
result = UUID.randomUUID ().toString ();
}
}
return result;
return result;
}
}
......
......@@ -16,6 +16,8 @@
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <jni.h>
#include <jvmti.h>
......@@ -104,15 +106,15 @@ static volatile bool jvm_is_initialized;
(((name) == NULL) ? "<unknown>" : (name))
#define rdaprefix(args...) \
rdoutput ("disl-agent: "); \
rdoutput (AGENT_NAME ": "); \
rdoutput (args);
#define rdatprefix(info, args...) \
rdoutput ("disl-agent [%s]: ", __safe_name ((info)->name)); \
rdoutput (AGENT_NAME " [%s]: ", __safe_name ((info)->name)); \
rdoutput (args);
#define rdatiprefix(info, args...) \
rdoutput ("disl-agent [%s, %" PRId64 "]: ", __safe_name ((info)->name), (info)->id); \
rdoutput (AGENT_NAME " [%s, %" PRId64 "]: ", __safe_name ((info)->name), (info)->id); \
rdoutput (args);
#define rdaprintf(args...) \
......@@ -176,38 +178,44 @@ __safe (const char * class_name) {
static bool
__instrument_class (
jint request_flags, const char * class_name,
jvmtiClassDefinition * class_def
jvmtiClassDefinition * class_def, const jlong classloader_tag
) {
//
// Put the class data into a request message, acquire a connection and
// send the it to the server. Receive the response and release the
// send the it to the server. Wait for a response and release the
// connection again.
//
ClientMessage message = CLIENT_MESSAGE__INIT;
message.session_id = agent_config.session_id;
ClassInfo class_info = CLASS_INFO__INIT;
class_info.classname = (char *) class_name;
class_info.classloadertag = classloader_tag;
InstrumentClassRequest request = INSTRUMENT_CLASS_REQUEST__INIT;
request.flags = request_flags;
request.classname = (char *) class_name;
request.classinfo = &class_info;
request.classbytes.len = class_def->class_byte_count;
request.classbytes.data = (uint8_t *) class_def->class_bytes;
message.request_case = CLIENT_MESSAGE__REQUEST_INSTRUMENT_CLASS_REQUEST;
message.instrument_class_request = &request;
struct connection * conn = network_acquire_connection ();
send_client_message(message, conn);
//
ServerMessage * resp = receive_server_message(conn);
struct connection * conn = network_acquire_connection ();
send_client_message (message, conn);
ServerMessage * resp = receive_server_message (conn);
network_release_connection(conn);
assert( resp->response_case == SERVER_MESSAGE__RESPONSE_INSTRUMENT_CLASS_RESPONSE );
InstrumentClassResponse * response = resp->instrument_class_response;
//
// Check if error occurred on the server.
// The control field of the response contains the error message.
// Check the response and if it indicates an error during instrumentation,
// bail out with an error message.
//
assert (resp->response_case == SERVER_MESSAGE__RESPONSE_INSTRUMENT_CLASS_RESPONSE);
InstrumentClassResponse * response = resp->instrument_class_response;
if (response->result == INSTRUMENT_CLASS_RESPONSE__INSTRUMENT_CLASS_RESULT__ERROR) {
fprintf (
stderr, AGENT_NAME ": instrumentation server error:\n%s\n",
......@@ -218,9 +226,8 @@ __instrument_class (
}
//
// Update the class definition and signal that the class has been
// modified if non-empty class code has been returned. Otherwise,
// signal that the class has not been modified.
// Update the class definition and signal whether the class has been
// modified at the server or not.
//
if (response->result == INSTRUMENT_CLASS_RESPONSE__INSTRUMENT_CLASS_RESULT__CLASS_MODIFIED) {
class_def->class_byte_count = response->classbytes.len;
......@@ -386,7 +393,7 @@ __thread_name (jvmtiEnv * jvmti, JNIEnv * jni) {
//
// Release the thread_group and context_class_loader
// references because we dont not need them.
// references because we do not need them.
//
if (jni != NULL) {
(* jni)->DeleteLocalRef (jni, info.thread_group);
......@@ -426,21 +433,79 @@ __thread_info_done (jvmtiEnv * jvmti, struct thread_info * info) {
}
#define CLASSLOADER_TAG_INITIAL 100000
#define CLASSLOADER_TAG_BOOTSTRAP 0
#define CLASSLOADER_TAG_UNKNOWN -1
static jlong classloader_tag_next = CLASSLOADER_TAG_INITIAL;
static pthread_mutex_t classloader_tag_mutex = PTHREAD_MUTEX_INITIALIZER;
static jlong
__get_classloader_tag (jvmtiEnv * jvmti, jobject loader) {
//
// If loader is NULL, then we are dealing with the bootstrap
// classloader. We cannot tag it, so it is assigned a special tag.
//
if (loader == NULL) {
return CLASSLOADER_TAG_BOOTSTRAP;
}
//
// In other cases, check if the classloader has a tag and if not,
// assign one to it. We can only do this when we are past the
// PRIMORDIAL phase when the JVMTI calls to get/set tag are allowed.
//
if (!jvm_is_started) {
return CLASSLOADER_TAG_UNKNOWN;
}
//
// Check the tag without a lock first and if present, just return it.
// If not, lock and check the tag again and assign one if unset.
//
rdaprintf ("getting tag for class loader 0x%p: ", loader);
jlong tag = jvmti_get_object_tag (jvmti, loader);
if (tag == 0) {
int lock_result = pthread_mutex_lock (&classloader_tag_mutex);
check_error (lock_result != 0, "failed to lock tagging mutex");
tag = jvmti_get_object_tag (jvmti, loader);
if (tag == 0) {
tag = classloader_tag_next++;
jvmti_set_object_tag (jvmti, loader, tag);
}
int unlock_result = pthread_mutex_unlock (&classloader_tag_mutex);
check_error (unlock_result != 0, "failed to unlock tagging mutex");
}
rdaprintf ("%" PRId64 "\n", tag);
return tag;
}
static void JNICALL
jvmti_callback_class_file_load (
jvmtiEnv * jvmti, JNIEnv * jni,
jclass class_being_redefined, jobject loader,
jclass class_being_redefined, jobject classloader,
const char * class_name, jobject protection_domain,
jint class_byte_count, const unsigned char * class_bytes,
jint * new_class_byte_count, unsigned char ** new_class_bytes
) {
//
// Get classloader tag or assign a new one.
//
jlong classloader_tag = __get_classloader_tag (jvmti, classloader);
struct thread_info info = INIT_THREAD_INFO;
rdexec {
__thread_info_init (jvmti, jni, &info);
rdatiprefix (
&info, "processing %s (%ld bytes)\n",
__safe (class_name), (long) class_byte_count
&info, "processing %s of classloader %" PRId64 " (%ld bytes)\n",
__safe (class_name), classloader_tag, (long) class_byte_count
);
}
......@@ -449,12 +514,12 @@ jvmti_callback_class_file_load (
//
if (class_name != NULL && strcmp (class_name, BPC_CLASS_NAME) == 0) {
rdatiprintf (&info, "ignored %s (bypass check class)\n", class_name);
return;
goto __release_thread_info;
}
//
// Force loading of the super class or the interface classes. This is
// only used when the VM is out of the primordial phase, which allows
// Force loading of the super class or the interface classes. This can
// only be done when the VM is out of the PRIMORDIAL phase, which allows
// JNI calls to be made.
//
if (agent_config.force_superclass || agent_config.force_interfaces) {
......@@ -476,7 +541,7 @@ jvmti_callback_class_file_load (
};
bool class_changed = __instrument_class (
agent_code_flags, class_name, &class_def
agent_code_flags, class_name, &class_def, classloader_tag
);
if (class_changed) {
......@@ -497,6 +562,7 @@ jvmti_callback_class_file_load (
rdatiprintf (&info, "loaded %s (unmodified)\n", __safe (class_name));
}
__release_thread_info:
rdexec {
__thread_info_done (jvmti, &info);
}
......@@ -799,7 +865,7 @@ Agent_OnLoad (JavaVM * jvm, char * options, void * reserved) {
rdaprintf ("agent loaded, initializing connections\n");
network_init (agent_config.server_host, agent_config.server_port);
session_start(&agent_config);
session_start (&agent_config);
return 0;
}
......
......@@ -232,6 +232,51 @@ void instrumentation_accept_confirmation__free_unpacked
assert(message->base.descriptor == &instrumentation_accept_confirmation__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void class_info__init
(ClassInfo *message)
{
static const ClassInfo init_value = CLASS_INFO__INIT;
*message = init_value;
}
size_t class_info__get_packed_size
(const ClassInfo *message)
{
assert(message->base.descriptor == &class_info__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t class_info__pack
(const ClassInfo *message,
uint8_t *out)
{
assert(message->base.descriptor == &class_info__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t class_info__pack_to_buffer
(const ClassInfo *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &class_info__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
ClassInfo *
class_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (ClassInfo *)
protobuf_c_message_unpack (&class_info__descriptor,
allocator, len, data);
}
void class_info__free_unpacked
(ClassInfo *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &class_info__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void instrument_class_request__init
(InstrumentClassRequest *message)
{
......@@ -692,29 +737,68 @@ const ProtobufCMessageDescriptor instrumentation_accept_confirmation__descriptor
(ProtobufCMessageInit) instrumentation_accept_confirmation__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor instrument_class_request__field_descriptors[3] =
static const ProtobufCFieldDescriptor class_info__field_descriptors[2] =
{
{
"flags",
"className",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(ClassInfo, classname),
NULL,
&protobuf_c_empty_string,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"classLoaderTag",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
PROTOBUF_C_TYPE_INT64,
0, /* quantifier_offset */
offsetof(InstrumentClassRequest, flags),
offsetof(ClassInfo, classloadertag),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned class_info__field_indices_by_name[] = {
1, /* field[1] = classLoaderTag */
0, /* field[0] = className */
};
static const ProtobufCIntRange class_info__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor class_info__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"ClassInfo",
"ClassInfo",
"ClassInfo",
"",
sizeof(ClassInfo),
2,
class_info__field_descriptors,
class_info__field_indices_by_name,
1, class_info__number_ranges,
(ProtobufCMessageInit) class_info__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor instrument_class_request__field_descriptors[4] =
{
{
"className",
3,
"flags",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_STRING,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
offsetof(InstrumentClassRequest, classname),
offsetof(InstrumentClassRequest, flags),
NULL,
NULL,
&protobuf_c_empty_string,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
......@@ -730,16 +814,42 @@ static const ProtobufCFieldDescriptor instrument_class_request__field_descriptor
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"classInfo",
5,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
0, /* quantifier_offset */
offsetof(InstrumentClassRequest, classinfo),
&class_info__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"superTypes",
6,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(InstrumentClassRequest, n_supertypes),
offsetof(InstrumentClassRequest, supertypes),
&class_info__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned instrument_class_request__field_indices_by_name[] = {
2, /* field[2] = classBytes */
1, /* field[1] = className */
1, /* field[1] = classBytes */
2, /* field[2] = classInfo */
0, /* field[0] = flags */
3, /* field[3] = superTypes */
};
static const ProtobufCIntRange instrument_class_request__number_ranges[1 + 1] =
static const ProtobufCIntRange instrument_class_request__number_ranges[2 + 1] =
{
{ 2, 0 },
{ 0, 3 }
{ 4, 1 },
{ 0, 4 }
};
const ProtobufCMessageDescriptor instrument_class_request__descriptor =
{
......@@ -749,10 +859,10 @@ const ProtobufCMessageDescriptor instrument_class_request__descriptor =
"InstrumentClassRequest",
"",
sizeof(InstrumentClassRequest),
3,
4,
instrument_class_request__field_descriptors,
instrument_class_request__field_indices_by_name,
1, instrument_class_request__number_ranges,
2, instrument_class_request__number_ranges,
(ProtobufCMessageInit) instrument_class_request__init,
NULL,NULL,NULL /* reserved[123] */
};
......
......@@ -20,6 +20,7 @@ typedef struct _SessionInitRequest SessionInitRequest;
typedef struct _SessionInitResponse SessionInitResponse;
typedef struct _InstrumentationDelivery InstrumentationDelivery;
typedef struct _InstrumentationAcceptConfirmation InstrumentationAcceptConfirmation;
typedef struct _ClassInfo ClassInfo;
typedef struct _InstrumentClassRequest InstrumentClassRequest;
typedef struct _InstrumentClassResponse InstrumentClassResponse;
typedef struct _CloseConnection CloseConnection;
......@@ -119,6 +120,17 @@ struct _InstrumentationAcceptConfirmation
, 0, 0,NULL }
struct _ClassInfo
{
ProtobufCMessage base;
char *classname;
int64_t classloadertag;
};
#define CLASS_INFO__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&class_info__descriptor) \
, (char *)protobuf_c_empty_string, 0 }
/*
* This is the request to the instrumentaion server to instrument attached class.
*/
......@@ -126,12 +138,14 @@ struct _InstrumentClassRequest
{
ProtobufCMessage base;
int32_t flags;
char *classname;
ClassInfo *classinfo;
ProtobufCBinaryData classbytes;
size_t n_supertypes;
ClassInfo **supertypes;
};
#define INSTRUMENT_CLASS_REQUEST__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&instrument_class_request__descriptor) \
, 0, (char *)protobuf_c_empty_string, {0,NULL} }
, 0, NULL, {0,NULL}, 0,NULL }
/*
......@@ -312,6 +326,25 @@ InstrumentationAcceptConfirmation *
void instrumentation_accept_confirmation__free_unpacked
(InstrumentationAcceptConfirmation *message,
ProtobufCAllocator *allocator);
/* ClassInfo methods */
void class_info__init
(ClassInfo *message);
size_t class_info__get_packed_size
(const ClassInfo *message);
size_t class_info__pack
(const ClassInfo *message,
uint8_t *out);
size_t class_info__pack_to_buffer
(const ClassInfo *message,
ProtobufCBuffer *buffer);
ClassInfo *
class_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void class_info__free_unpacked
(ClassInfo *message,
ProtobufCAllocator *allocator);
/* InstrumentClassRequest methods */
void instrument_class_request__init
(InstrumentClassRequest *message);
......@@ -424,6 +457,9 @@ typedef void (*InstrumentationDelivery_Closure)
typedef void (*InstrumentationAcceptConfirmation_Closure)
(const InstrumentationAcceptConfirmation *message,
void *closure_data);
typedef void (*ClassInfo_Closure)
(const ClassInfo *message,
void *closure_data);
typedef void (*InstrumentClassRequest_Closure)
(const InstrumentClassRequest *message,
void *closure_data);
......@@ -450,6 +486,7 @@ extern const ProtobufCMessageDescriptor session_init_request__descriptor;
extern const ProtobufCMessageDescriptor session_init_response__descriptor;
extern const ProtobufCMessageDescriptor instrumentation_delivery__descriptor;
extern const ProtobufCMessageDescriptor instrumentation_accept_confirmation__descriptor;
extern const ProtobufCMessageDescriptor class_info__descriptor;
extern const ProtobufCMessageDescriptor instrument_class_request__descriptor;
extern const ProtobufCMessageDescriptor instrument_class_response__descriptor;
extern const ProtobufCEnumDescriptor instrument_class_response__instrument_class_result__descriptor;
......
......@@ -2239,6 +2239,8 @@ merge_messages(ProtobufCMessage *earlier_msg,
latter_msg->descriptor
->field_ranges,
*earlier_case_p);
if (field_index < 0)
return FALSE;
field = latter_msg->descriptor->fields +
field_index;
} else {
......@@ -2632,6 +2634,8 @@ parse_oneof_member (ScannedMember *scanned_member,
int_range_lookup(message->descriptor->n_field_ranges,
message->descriptor->field_ranges,
*oneof_case);
if (field_index < 0)
return FALSE;
const ProtobufCFieldDescriptor *old_field =
message->descriptor->fields + field_index;
size_t el_size = sizeof_elt_in_repeated_array(old_field->type);
......
/*
* Copyright (c) 2008-2017, Dave Benson and the protobuf-c authors.
* Copyright (c) 2008-2018, Dave Benson and the protobuf-c authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -790,13 +790,13 @@ protobuf_c_version_number(void);
* The version of the protobuf-c headers, represented as a string using the same
* format as protobuf_c_version().
*/
#define PROTOBUF_C_VERSION "1.3.0"
#define PROTOBUF_C_VERSION "1.3.1"
/**
* The version of the protobuf-c headers, represented as an integer using the
* same format as protobuf_c_version_number().
*/
#define PROTOBUF_C_VERSION_NUMBER 1003000
#define PROTOBUF_C_VERSION_NUMBER 1003001
/**
* The minimum protoc-c version which works with the current version of the
......
......@@ -14,7 +14,6 @@
#include "connection.h"
#include "config.h"
#include "protobuf-c.h"
#include "dislserver.pb-c.h"
void
......
......@@ -37,11 +37,17 @@ message InstrumentationAcceptConfirmation {
repeated Error errors = 2;
}
message ClassInfo {
string className = 1;
int64 classLoaderTag = 2;
}
// This is the request to the instrumentaion server to instrument attached class.
message InstrumentClassRequest {
int32 flags = 2;
string className = 3;
ClassInfo classInfo = 5;
bytes classBytes = 4;
repeated ClassInfo superTypes = 6;
}
// Server response containing either the instrumented classbytes or error message
......