Commit 1830d6a1 authored by Vít Kabele's avatar Vít Kabele

Disl agent instrumentations now passes in -Ddisl.instrumentation property.

Parsing is done in config section.
parent 1c851f63
Pipeline #3509 passed with stages
in 3 minutes and 10 seconds
......@@ -484,7 +484,8 @@ def run_client(args, parser):
c_cmd = ["java"]
c_cmd+= args.c_opts
c_cmd+= ["-agentpath:"+cagent+"="+args.instrumentation]
c_cmd+= ["-agentpath:"+cagent]
c_cmd+= ["-Ddisl.instrumentation="+args.instrumentation]
if args.cse == True:
c_cmd+= ["-agentpath:"+eagent]
......
......@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
//
......@@ -49,6 +50,33 @@ die_with_std_error (const char * message, int errnum) {
exit (ERROR_STD);
}
// ****************************************************************************
// STRING UTILS SECTION
// ****************************************************************************
size_t
substr_count(const char * string, const char * restrict substr) {
size_t count = 0;
for(const char * token = string; (token = strstr(token, substr)) != NULL; ++token)
{
++count;
}
return (count);
}
char **
split_string(char * string, const char * restrict separator, size_t * tkns) {
size_t tokens = substr_count(string, separator) + 1;
assert(tokens > 0);
char ** arr = malloc(tokens * sizeof(char *));
arr[0] = strtok(string, separator);
for(size_t i = 1; i < tokens; ++i)
arr[i] = strtok(NULL, separator);
*tkns = tokens;
return (arr);
}
#ifdef MINGW
......
......@@ -6,6 +6,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/types.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
......@@ -87,6 +88,30 @@ int find_value_index (const char * strval, const char * values [], int nvals);
void die_with_error (const char * message);
void die_with_std_error (const char * message, int errnum);
// ****************************************************************************
// STRING UTILS SECTION
// ****************************************************************************
/**
* Count the occurrences of substr in string
* @param string
* @param substr
* @return
*/
size_t
substr_count(const char * string, const char * restrict substr);
/**
* Split the string into tokens
* Remember to free the result.
*
* @param string The string to split
* @param separator
* @param tokens Pointer to the size_t variable to store the number of tokens
* @return
*/
char **
split_string(char * string, const char * restrict separator, size_t * tokens);
/**
* Reports a general error and terminates the program if the provided
......
/**
* This file is part of src_disl_agent
*
* Created by Vít Kabele on 25/11/2018.
*/
#include "config.h"
/**
* This file is part of src_disl_agent
*
* Created by Vít Kabele on 25/11/2018.
*/
#ifndef SRC_DISL_AGENT_CONFIG_H
#define SRC_DISL_AGENT_CONFIG_H
#include "common.h"
#include <sys/types.h>
/**
* The instrumentation bypass mode.
* NOTE: The ordering of the modes is important!
*/
enum bypass_mode {
/**
* The original method code will not be preserved. Consequently, the
* instrumented version of a method will be always executed, even when
* invoked inside a DiSL snippet.
*/
BYPASS_MODE_DISABLED = 0,
/**
* The original method code will be preserved, and will be always
* executed instead of the instrumented version during JVM bootstrap.
* After bootstrap, only the instrumented version of a method will
* be executed.
*/
BYPASS_MODE_BOOTSTRAP = 1,
/**
* The original method code will be preserved, and executed whenever
* invoked from inside a DiSL snippet.
*/
BYPASS_MODE_DYNAMIC = 2
};
/**
* The agent configuration
*/
struct config {
char * server_host;
char * server_port;
int32_t session_id;
size_t jar_count;
char ** instrumentation_jars;
enum bypass_mode bypass_mode;
bool split_methods;
bool catch_exceptions;
bool force_superclass;
bool force_interfaces;
bool debug;
};
#endif //SRC_DISL_AGENT_CONFIG_H
#include "common.h"
#include "config.h"
#include "jvmtiutil.h"
#include "connection.h"
......@@ -26,6 +27,11 @@
#define DISL_SERVER_HOST "disl.server.host"
#define DISL_SERVER_HOST_DEFAULT "localhost"
// Required argument
// No default value.
#define DISL_INSTRUMENTATION "disl.instrumentation"
#define LIST_SEPARATOR ":"
#define DISL_SERVER_PORT "disl.server.port"
#define DISL_SERVER_PORT_DEFAULT "11217"
......@@ -48,34 +54,6 @@
#define DISL_DEBUG_DEFAULT false
/**
* The instrumentation bypass mode.
* NOTE: The ordering of the modes is important!
*/
enum bypass_mode {
/**
* The original method code will not be preserved. Consequently, the
* instrumented version of a method will be always executed, even when
* invoked inside a DiSL snippet.
*/
BYPASS_MODE_DISABLED = 0,
/**
* The original method code will be preserved, and will be always
* executed instead of the instrumented version during JVM bootstrap.
* After bootstrap, only the instrumented version of a method will
* be executed.
*/
BYPASS_MODE_BOOTSTRAP = 1,
/**
* The original method code will be preserved, and executed whenever
* invoked from inside a DiSL snippet.
*/
BYPASS_MODE_DYNAMIC = 2
};
/**
* Flags representing code options, derived from the values generated from Java.
*/
......@@ -87,20 +65,6 @@ enum code_flags {
};
struct config {
char * server_host;
char * server_port;
enum bypass_mode bypass_mode;
bool split_methods;
bool catch_exceptions;
bool force_superclass;
bool force_interfaces;
bool debug;
};
/**
* Agent configuration.
*/
......@@ -220,7 +184,7 @@ __instrument_class (
// connection again.
//
ClientMessage message = CLIENT_MESSAGE__INIT;
message.session_id = session_id;
message.session_id = agent_config.session_id;
InstrumentClassRequest request = INSTRUMENT_CLASS_REQUEST__INIT;
request.flags = request_flags;
request.classname = (char *) class_name;
......@@ -621,6 +585,22 @@ jvmti_callback_vm_death (jvmtiEnv * jvmti, JNIEnv * jni) {
// AGENT ENTRY POINT: ON LOAD
// ****************************************************************************
/**
* Parse the instrumentation jar list in format "jar:jar2:...:jarN" to agent_config struct.
*
* @param list The list of jar files separated by :
* @param config
*/
static void
__parse_instrumentations( char * list, struct config * config ){
size_t jar_count;
char ** jar_paths = split_string(list, LIST_SEPARATOR, &jar_count);
config->jar_count = jar_count;
config->instrumentation_jars = jar_paths;
}
static void
__configure_from_properties (jvmtiEnv * jvmti, struct config * config) {
//
......@@ -637,6 +617,15 @@ __configure_from_properties (jvmtiEnv * jvmti, struct config * config) {
config->bypass_mode = bypass_index;
free (bypass);
//
// Get instrumentation list
//
char * instrumentation = jvmti_get_system_property_string(
jvmti, DISL_INSTRUMENTATION, NULL
);
assert(instrumentation != NULL);
__parse_instrumentations(instrumentation, config);
//
// Get boolean values from system properties
//
......@@ -749,7 +738,7 @@ Agent_OnLoad (JavaVM * jvm, char * options, void * reserved) {
// configure agent and init connections
__configure_from_options (NULL, &agent_config);
__configure_from_options (options, &agent_config);
__configure_from_properties (jvmti, &agent_config);
jvm_is_started = false;
......@@ -759,9 +748,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);
int32_t sid = session_start(options);
rdaprintf("Obtained session id is %i\n", sid);
session_start(&agent_config);
// register callbacks
jvmtiEventCallbacks callbacks = {
......
......@@ -56,30 +56,6 @@ struct inst_jar {
long filesize;
};
static size_t
substr_count(const char * string, const char * restrict substr) {
size_t count = 0;
for(const char * token = string; (token = strstr(token, substr)) != NULL; ++token)
++count;
return (count);
}
/*
* Free the return value after use.
*/
static char **
split_string(char * string, const char * restrict separator) {
size_t tokens = substr_count(string, separator) + 1;
assert(tokens > 0);
char ** arr = malloc(tokens * sizeof(char *));
arr[0] = strtok(string, separator);
for(size_t i = 1; i < tokens; ++i)
arr[i] = strtok(NULL, separator);
return (arr);
}
/*
* Get filesize
*/
......@@ -91,27 +67,24 @@ get_filesize(const char * filename){
return buffer.st_size;
}
/*
* Load the instrumentation.
* Options should be field of paths pointing to a *.jar files separated by semicolon (:)
/**
* Instrumentation delivery message build
* @param config
* @return
*/
InstrumentationDelivery
load_instrumentation(char * restrict options){
static InstrumentationDelivery
instrumentationDeliveryInit(struct config * config){
InstrumentationDelivery delivery = INSTRUMENTATION_DELIVERY__INIT;
if(options == NULL)
return delivery;
size_t tokens = config->jar_count;
char ** arr = config->instrumentation_jars;
size_t tokens = substr_count(options, ":") + 1;
struct inst_jar * jars = malloc(tokens * sizeof(struct inst_jar));
size_t total_size = 0;
delivery.n_sizes = tokens;
delivery.sizes = malloc( tokens * sizeof(int32_t));
// Allocate an array of filenames/paths
char ** arr = split_string(options,":");
for(size_t i = 0; i < tokens; ++i){
jars[i].name = arr[i];
}
......@@ -147,8 +120,8 @@ load_instrumentation(char * restrict options){
return (delivery);
}
int32_t
session_start(char * restrict options) {
void
session_start(struct config * config) {
struct connection * conn = network_acquire_connection();
int32_t sid = 0;
......@@ -168,14 +141,13 @@ session_start(char * restrict options) {
sid = response->session_init_response->session_id;
assert(sid != 0);
session_id = sid;
server_message__free_unpacked(response, NULL);
}
{
ClientMessage message = CLIENT_MESSAGE__INIT;
InstrumentationDelivery delivery = load_instrumentation(options);
InstrumentationDelivery delivery = instrumentationDeliveryInit(config);
message.request_case = CLIENT_MESSAGE__REQUEST_INSTRUMENTATION_DELIVERY;
message.session_id = sid;
message.instrumentation_delivery = &delivery;
......@@ -191,12 +163,12 @@ session_start(char * restrict options) {
network_release_connection(conn);
return (sid);
config->session_id = sid;
}
void
session_end() {
session_end(struct config * config) {
struct connection * conn = network_acquire_connection();
ClientMessage message = CLIENT_MESSAGE__INIT;
......@@ -204,7 +176,7 @@ session_end() {
cc.reason = CLOSE_CONNECTION__CLOSE_REASON__FINISHED;
message.request_case = CLIENT_MESSAGE__REQUEST_CLOSE_CONNECTION;
message.session_id = session_id;
message.session_id = config->session_id;
message.close_connection = &cc;
send_client_message(message, conn);
......
......@@ -12,35 +12,29 @@
#include "msgchannel.h"
#include "connection.h"
#include "config.h"
#include "protobuf-c.h"
#include "dislserver.pb-c.h"
/*
* Global variable that holds the id of the session.
* Zero means that there is no active session initiated.
*/
int32_t session_id;
void
send_client_message(ClientMessage message, struct connection * conn);
ServerMessage *
receive_server_message(struct connection * conn);
/*
/**
* Negotiate the session with the server.
*
* @return Obtained session id.
*/
int32_t
session_start(char * options);
void
session_start(struct config * config);
/*
/**
* Announce the end of the session to the server.
*/
void
session_end();
session_end(struct config * config);
#endif /* _SESSIONS_H_ */
......@@ -121,7 +121,8 @@ public class ClientServerEvaluationRunner extends Runner {
) throws IOException {
final List <String> command = new LinkedList <> (Arrays.asList (
__CLIENT_JAVA_COMMAND__, "-noverify",
String.format ("-agentpath:%s=%s", _DISL_AGENT_LIB_, instJar.getPath ()),
String.format ("-agentpath:%s", _DISL_AGENT_LIB_),
String.format ("-Ddisl.instrumentation=%s", instJar.getPath ()),
String.format ("-agentpath:%s", _SHVM_AGENT_LIB_),
String.format ("-Xbootclasspath/a:%s", Runner.classPath (
_DISL_BYPASS_JAR_, _SHVM_DISPATCH_JAR_, instJar
......
......@@ -86,7 +86,8 @@ public class ClientServerRunner extends Runner {
) throws IOException {
final List <String> command = new LinkedList <> (Arrays.asList (
__CLIENT_JAVA_COMMAND__, "-noverify",
String.format ("-agentpath:%s=%s", _DISL_AGENT_LIB_, testInstJar.getPath ()),
String.format ("-agentpath:%s", _DISL_AGENT_LIB_),
String.format ("-Ddisl.instrumentation=%s", testInstJar.getPath ()),
String.format ("-Xbootclasspath/a:%s", Runner.classPath (
_DISL_BYPASS_JAR_, testInstJar
))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment