...
 
Commits (13)
......@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
......@@ -31,8 +32,11 @@ find_value_index (const char * strval, const char * values [], int nvals) {
* an error code indicating a generic error.
*/
void
die_with_error (const char * message) {
fprintf (stderr, "%s%s\n", ERROR_PREFIX, message);
die_with_error (const char * restrict format, va_list args) {
fprintf (stderr, AGENT_NAME ": error: ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_GENERIC);
}
......@@ -44,15 +48,22 @@ die_with_error (const char * message) {
* exits with an error code indicating failure in standard library call.
*/
void
die_with_std_error (const char * message, int errnum) {
die_with_std_error (int errnum, const char * restrict format, va_list args) {
char * cause = strerror (errnum);
fprintf (stderr, "%s%s\ncause: %s\n", ERROR_PREFIX, message, cause);
fprintf (stderr, AGENT_NAME ": std-error: %s\n", cause);
fprintf (stderr, AGENT_NAME ": ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_STD);
}
// ****************************************************************************
// STRING UTILS SECTION
// ****************************************************************************
size_t
substr_count(const char * string, const char * restrict substr) {
size_t count = 0;
......@@ -117,13 +128,17 @@ __get_error_message (const DWORD msg_id) {
* exits with an error code indicating failure in standard library call.
*/
void
die_with_win_error (const char * message, DWORD errnum) {
char * cause = __get_error_message (errnum);
fprintf (stderr, "%s%s\ncause: %s", ERROR_PREFIX, message, cause);
die_with_win_error (DWORD errnum, const char * restrict format, va_list args) {
const char * restrict cause = __get_error_message (errnum);
fprintf (stderr, AGENT_NAME ": std-error: %s\n", cause);
if (cause != NULL) {
free (cause);
}
fprintf (stderr, AGENT_NAME ": ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_STD);
}
......
......@@ -4,9 +4,9 @@
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/types.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
......@@ -45,26 +45,12 @@
/**
* Prints a debug message to stdout, unless NDEBUG is defined.
* Prints a warning message to stderr.
*
* @format format string for printf
* @args arguments associated with the format string
*
*/
#ifdef NDEBUG
# define debug(args...) do {} while (0)
#else
# define debug(args...) fprintf (stdout, args); fflush (stdout)
#endif
#define ldebug(args...) { \
debug ("%s:%d: ", __FUNCTION__, __LINE__); \
debug (args); \
}
//
#define warn(args...) { \
fprintf (stderr, "warning: "); \
fprintf (stderr, args); \
......@@ -81,46 +67,27 @@ int find_value_index (const char * strval, const char * values [], int nvals);
#define ERROR_STD 10002
#define ERROR_JVMTI 10003
#define ERROR_PREFIX "disl-agent: error: "
#define AGENT_NAME "disl-agent"
//
void die_with_error (const char * message);
void die_with_std_error (const char * message, int errnum);
void die_with_error (const char * format, va_list args);
void die_with_std_error (int errnum, const char * format, va_list args);
// ****************************************************************************
// 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
* error condition is true.
*/
static inline void
check_error (bool error, const char * message) {
check_error (bool error, const char * format, ...) {
if (error) {
die_with_error (message);
va_list args;
va_start (args, format);
die_with_error (format, args);
va_end (args);
}
}
......@@ -130,9 +97,14 @@ check_error (bool error, const char * message) {
* error condition is true.
*/
static inline void
check_std_error (bool error, const char * message) {
check_std_error (bool error, const char * format, ...) {
if (error) {
die_with_std_error (message, errno);
va_list args;
va_start (args, format);
die_with_std_error (errno, format, args);
va_end (args);
}
}
......@@ -148,11 +120,38 @@ warn_std_error (bool error, const char * message) {
}
}
// ****************************************************************************
// 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);
//
#ifdef MINGW
void die_with_win_error (const char * message, DWORD errnum);
void die_with_win_error (DWORD errnum, const char * message, va_list args);
/**
......@@ -160,13 +159,17 @@ void die_with_win_error (const char * message, DWORD errnum);
* error condition is true.
*/
static inline void
check_win_error (bool error, const char * message) {
check_win_error (bool error, const char * format, ...) {
if (error) {
die_with_win_error (message, GetLastError ());
va_list args;
va_start (args, format);
die_with_win_error (GetLastError (), format, args);
va_end (args);
}
}
#endif /* MINGW */
#endif /* _COMMON_H_ */
#include "common.h"
#include "debug.h"
#include "connection.h"
#include <assert.h>
......
#include "common.h"
#include "debug.h"
#include "list.h"
#include "connection.h"
#include "connpool.h"
......
#ifndef _DEBUG_H_
#define _DEBUG_H_
#include <stdio.h>
/**
* Prints a debug message to stdout, unless NDEBUG is defined.
*
* @format format string for printf
* @args arguments associated with the format string
*/
#ifdef NDEBUG
# define debug(args...) do {} while (0)
#else
# define debug(args...) fprintf (stdout, args); fflush (stdout)
#endif
/**
* Prints a debug message to stdout prefixed with the name of
* the function and the source code line, unless NDEBUG is defined.
*
* @format format string for printf
* @args arguments associated with the format string
*/
#define ldebug(args...) { \
debug ("%s:%d: ", __FUNCTION__, __LINE__); \
debug (args); \
}
#endif /* _DEBUG_H_ */
......@@ -210,8 +210,8 @@ __instrument_class (
//
if (response->result == INSTRUMENT_CLASS_RESPONSE__INSTRUMENT_CLASS_RESULT__ERROR) {
fprintf (
stderr, "%sinstrumentation server error:\n%s\n",
ERROR_PREFIX, response->errormessage
stderr, AGENT_NAME ": instrumentation server error:\n%s\n",
response->errormessage
);
exit (ERROR_SERVER);
......@@ -709,11 +709,11 @@ __get_jvmti (JavaVM * jvm) {
// JVMTI interface. This is a fatal error for the agent.
//
fprintf (
stderr,
"%sFailed to obtain JVMTI interface Version 1 (0x%x)\n"
stderr, AGENT_NAME "error: "
"Failed to obtain JVMTI interface Version 1 (0x%x)\n"
"JVM GetEnv() returned %ld - is your Java runtime "
"version 1.5 or newer?\n",
ERROR_PREFIX, JVMTI_VERSION_1, (long) result
JVMTI_VERSION_1, (long) result
);
exit (ERROR_JVMTI);
......@@ -723,34 +723,50 @@ __get_jvmti (JavaVM * jvm) {
}
static void
__jvmti_add_capabilities (jvmtiEnv * jvmti, const jvmtiCapabilities * caps) {
jvmtiError error = (*jvmti)->AddCapabilities (jvmti, caps);
check_jvmti_error (jvmti, error, "failed to add JVMTI capabilities");
}
static void
__jvmti_register_callbacks (
jvmtiEnv * jvmti, const jvmtiEventCallbacks * callbacks, size_t size
) {
jvmtiError error = (*jvmti)->SetEventCallbacks (jvmti, callbacks, (jint) size);
check_jvmti_error (jvmti, error, "failed to register event callbacks");
}
static void
__jvmti_enable_events (jvmtiEnv * jvmti, jvmtiEvent * events, size_t count) {
for (unsigned int i = 0; i < count; i++) {
jvmtiEvent event = events [i];
jvmtiError error = (*jvmti)->SetEventNotificationMode (
jvmti, JVMTI_ENABLE, event, NULL
);
check_jvmti_error (jvmti, error, "failed to enable JVMTI event 0x%x", event);
}
}
JNIEXPORT jint JNICALL VISIBLE
Agent_OnLoad (JavaVM * jvm, char * options, void * reserved) {
jvmtiEnv * jvmti = __get_jvmti (jvm);
// add capabilities
// Request JVMTI capabilities:
jvmtiCapabilities caps = {
.can_redefine_classes = 1,
.can_generate_all_class_hook_events = 1,
.can_tag_objects = 1,
};
jvmtiError error = (*jvmti)->AddCapabilities (jvmti, &caps);
check_jvmti_error (jvmti, error, "failed to add capabilities");
__jvmti_add_capabilities (jvmti, &caps);
// configure agent and init connections
__configure_from_options (options, &agent_config);
__configure_from_properties (jvmti, &agent_config);
jvm_is_started = false;
jvm_is_initialized = false;
agent_code_flags = __calc_code_flags (&agent_config, true);
rdaprintf ("agent loaded, initializing connections\n");
network_init (agent_config.server_host, agent_config.server_port);
session_start(&agent_config);
// register callbacks
// Register JVMTI event callbacks.
jvmtiEventCallbacks callbacks = {
.VMStart = &jvmti_callback_vm_start,
.VMInit = &jvmti_callback_vm_init,
......@@ -758,23 +774,32 @@ Agent_OnLoad (JavaVM * jvm, char * options, void * reserved) {
.ClassFileLoadHook = &jvmti_callback_class_file_load,
};
error = (*jvmti)->SetEventCallbacks (jvmti, &callbacks, (jint) sizeof (callbacks));
check_jvmti_error (jvmti, error, "failed to register event callbacks");
__jvmti_register_callbacks (jvmti, &callbacks, sizeof (callbacks));
// enable event notification
error = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, NULL);
check_jvmti_error (jvmti, error, "failed to enable VM START event");
// Enable JVMTI events globally for all threads.
jvmtiEvent events [] = {
JVMTI_EVENT_VM_START,
JVMTI_EVENT_VM_INIT,
JVMTI_EVENT_VM_DEATH,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
};
error = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
check_jvmti_error (jvmti, error, "failed to enable VM INIT event");
__jvmti_enable_events (jvmti, events, sizeof_array (events));
error = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
check_jvmti_error (jvmti, error, "failed to enable VM DEATH event");
error = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
check_jvmti_error (jvmti, error, "failed to enable CLASS FILE LOAD event");
// configure agent and init connections
__configure_from_options (options, &agent_config);
__configure_from_properties (jvmti, &agent_config);
jvm_is_started = false;
jvm_is_initialized = false;
agent_code_flags = __calc_code_flags (&agent_config, true);
rdaprintf ("agent loaded, initializing connections\n");
network_init (agent_config.server_host, agent_config.server_port);
session_start(&agent_config);
return 0;
}
......
......@@ -10,8 +10,8 @@
//
#ifndef ERROR_PREFIX
#error ERROR_PREFIX macro has to be defined
#ifndef AGENT_NAME
#error AGENT_NAME macro has to be defined
#endif
#ifndef ERROR_JVMTI
......@@ -168,6 +168,31 @@ jvmti_get_system_property_string (
}
/**
* Gets tag from the given object. This method can only be called
* during the START and LIVE phases.
*/
jlong
jvmti_get_object_tag (jvmtiEnv * jvmti, jobject object) {
jlong tag;
jvmtiError error = (*jvmti)->GetTag (jvmti, object, &tag);
check_jvmti_error (jvmti, error, "failed to get object tag");
return tag;
}
/**
* Sets a tag to the given object. This method can only be called
* during the START and LIVE phases.
*/
jlong
jvmti_set_object_tag (jvmtiEnv * jvmti, jobject object, jlong tag) {
jvmtiError error = (*jvmti)->SetTag (jvmti, object, tag);
check_jvmti_error (jvmti, error, "failed to set object tag");
return tag;
}
/**
* Reports a JVMTI error and terminates the program. This function implements
* the slow path of check_jvmti_error() and prints the given error message
......@@ -175,16 +200,25 @@ jvmti_get_system_property_string (
* interface.
*/
void
die_with_jvmti_error (jvmtiEnv *jvmti, jvmtiError errnum, const char *str) {
char * errnum_str = NULL;
(void) (*jvmti)->GetErrorName (jvmti, errnum, &errnum_str);
die_with_jvmti_error (
jvmtiEnv * jvmti, jvmtiError error,
const char * restrict format, va_list args
) {
// JVMTI error
char * cause = NULL;
(void) (*jvmti)->GetErrorName (jvmti, error, &cause);
fprintf (
stderr, "%sJVMTI: %d (%s): %s\n",
ERROR_PREFIX, errnum,
(errnum_str == NULL ? "Unknown" : errnum_str),
(str == NULL ? "" : str)
stderr, AGENT_NAME ": jvmti-error: %s (%d)\n",
(cause != NULL) ? cause : "unknown", error
);
(*jvmti)->Deallocate (jvmti, (unsigned char *) cause);
// agent error
fprintf (stderr, AGENT_NAME ": ");
vfprintf (stderr, format, args);
fprintf (stderr, "\n");
exit (ERROR_JVMTI);
}
......@@ -3,12 +3,14 @@
#include "common.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <jvmti.h>
//
void die_with_jvmti_error (jvmtiEnv * jvmti, jvmtiError error, const char * message);
unsigned char * jvmti_alloc_copy (jvmtiEnv * jvmti, const void * src, size_t size);
bool jvmti_redefine_class (
......@@ -24,6 +26,16 @@ char * jvmti_get_system_property_string (
jvmtiEnv * jvmti, const char * name, const char * dflval
);
jlong jvmti_get_object_tag (jvmtiEnv * jvmti, jobject object);
jlong jvmti_set_object_tag (jvmtiEnv * jvmti, jobject object, jlong tag);
//
void die_with_jvmti_error (
jvmtiEnv * jvmti, jvmtiError error, const char * format, va_list args
);
/**
* Checks whether a JVMTI invocation returned an error. Every JVMTI interface
......@@ -31,9 +43,17 @@ char * jvmti_get_system_property_string (
* down the line.
*/
static inline void
check_jvmti_error(jvmtiEnv *jvmti, jvmtiError errnum, const char * message) {
check_jvmti_error (
jvmtiEnv * restrict jvmti, jvmtiError errnum,
const char * restrict format, ...
) {
if (errnum != JVMTI_ERROR_NONE) {
die_with_jvmti_error (jvmti, errnum, message);
va_list args;
va_start (args, format);
die_with_jvmti_error (jvmti, errnum, format, args);
va_end (args);
}
}
......
#include "common.h"
#include "debug.h"
#include "msgchannel.h"
#include "connection.h"
......
#include "common.h"
#include "debug.h"
#include "threads.h"
#include "connpool.h"
#include "connection.h"
......
......@@ -43,12 +43,12 @@ send_client_message(
*/
ServerMessage *
receive_server_message(struct connection * restrict conn) {
void * buffer;
ServerMessage * response;
void * buffer;
size_t recv_size = message_recv(conn, &buffer); // FREE!
response = server_message__unpack(NULL, recv_size, buffer);
ServerMessage * response = server_message__unpack(NULL, recv_size, buffer);
assert(response != NULL);
free(buffer); // FREEING!
return (response);
}
......@@ -68,32 +68,45 @@ struct inst_jar {
static long
get_filesize(const char * filename) {
struct stat buffer;
int status;
status = stat(filename, &buffer);
int result = stat(filename, &buffer);
check_std_error (result != 0, "failed to determine size of %s", filename);
return (buffer.st_size);
}
static void
__load_file (const char * name, void ** buffer, size_t * size) {
FILE * file = fopen (name, "r");
check_std_error (file == NULL, "failed to open %s", name);
size_t file_size = (size_t) get_filesize (name);
void * file_data = malloc (file_size);
check_std_error (file_data == NULL, "failed to allocate buffer for %s", name);
size_t bytes_read = fread (file_data, 1, file_size, file);
check_std_error (bytes_read != file_size, "failed to load %s", name);
fclose (file);
*buffer = file_data;
*size = file_size;
}
/*
* Load the files to the buffers.
* @return
*/
static void
load_files_to_buffers(struct inst_jar * jars, const size_t count) {
FILE * file;
// Open the files and ensure that all of them exists
// Load all instrumentation jars or fail.
for (size_t i = 0; i < count; ++i) {
file = fopen(jars[i].name, "r");
assert(file != NULL);
jars[i].filesize = (size_t)get_filesize(jars[i].name);
jars[i].buffer = malloc(jars[i].filesize);
fread(jars[i].buffer, 1, jars[i].filesize, file);
fclose(file);
struct inst_jar * jar = &(jars [i]);
__load_file (jar->name, &(jar->buffer), &(jar->filesize));
}
}
/*
* Instrumentation delivery message build
* @param config
......