Last active
April 11, 2025 01:00
-
-
Save apangin/28e24cd5d4aa235c329884f0cfb4868e to your computer and use it in GitHub Desktop.
JVM TI agent that continuously bombards C2 Compiler threads with no-op signals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <jvmti.h> | |
#include <dirent.h> | |
#include <dlfcn.h> | |
#include <fcntl.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/syscall.h> | |
#include <unistd.h> | |
static int is_compiler_thread(int tid) { | |
char buf[64]; | |
snprintf(buf, sizeof(buf), "/proc/self/task/%d/comm", tid); | |
int fd = open(buf, O_RDONLY); | |
if (fd == -1) { | |
return 0; | |
} | |
ssize_t r = read(fd, buf, sizeof(buf)); | |
close(fd); | |
return r > 0 && strncmp(buf, "C2 Compiler", 11) == 0; | |
} | |
static void* signaling_loop(void* unused) { | |
pid_t self = getpid(); | |
unsigned int counter = 0; | |
DIR* dir = opendir("/proc/self/task"); | |
if (dir == NULL) { | |
return NULL; | |
} | |
while (1) { | |
struct dirent* entry; | |
while ((entry = readdir(dir)) != NULL) { | |
if (entry->d_name[0] != '.') { | |
int tid = atoi(entry->d_name); | |
if (is_compiler_thread(tid)) { | |
syscall(__NR_tgkill, self, tid, SIGPROF); | |
} | |
} | |
} | |
rewinddir(dir); | |
} | |
} | |
#define BUF_SIZE 262144 | |
struct { | |
void* pc; | |
int tid; | |
} pcdesc[BUF_SIZE]; | |
static unsigned int ptr = 0; | |
void px(int tid) { | |
unsigned int p = ptr; | |
for (unsigned int i = 0; i < p; i++) { | |
if (pcdesc[i].tid == tid) { | |
const char* sym = "."; | |
Dl_info info; | |
if (dladdr(pcdesc[i].pc, &info) && info.dli_sname != NULL) { | |
sym = info.dli_sname; | |
} | |
printf("%5d %p %s\n", i, pcdesc[i].pc, sym); | |
} | |
} | |
} | |
static void noop_handler(int signo, siginfo_t* siginfo, void* ucontext) { | |
unsigned int p = __sync_fetch_and_add(&ptr, 1) & (BUF_SIZE - 1); | |
pcdesc[p].pc = (void*)((ucontext_t*)ucontext)->uc_mcontext.pc; | |
pcdesc[p].tid = syscall(__NR_gettid); | |
} | |
static void start_agent_thread() { | |
struct sigaction sa; | |
sigemptyset(&sa.sa_mask); | |
sa.sa_sigaction = noop_handler; | |
sa.sa_flags = SA_SIGINFO | SA_RESTART; | |
sigaction(SIGPROF, &sa, NULL); | |
pthread_t thread; | |
if (pthread_create(&thread, NULL, signaling_loop, NULL) == 0) { | |
printf("signaling_loop started\n"); | |
} | |
} | |
jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { | |
start_agent_thread(); | |
return 0; | |
} | |
jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { | |
start_agent_thread(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <dirent.h> | |
#include <fcntl.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/syscall.h> | |
#include <unistd.h> | |
static int is_compiler_thread(int tid) { | |
char buf[64]; | |
snprintf(buf, sizeof(buf), "/proc/self/task/%d/comm", tid); | |
int fd = open(buf, O_RDONLY); | |
if (fd == -1) { | |
return 0; | |
} | |
ssize_t r = read(fd, buf, sizeof(buf)); | |
close(fd); | |
return r > 0 && strncmp(buf, "C2 Compiler", 11) == 0; | |
} | |
static void* signaling_loop(void* unused) { | |
pid_t self = getpid(); | |
unsigned int counter = 0; | |
DIR* dir = opendir("/proc/self/task"); | |
if (dir == NULL) { | |
return NULL; | |
} | |
while (1) { | |
struct dirent* entry; | |
while ((entry = readdir(dir)) != NULL) { | |
if (entry->d_name[0] != '.') { | |
int tid = atoi(entry->d_name); | |
if (is_compiler_thread(tid)) { | |
syscall(__NR_tgkill, self, tid, SIGPROF); | |
} | |
} | |
} | |
rewinddir(dir); | |
} | |
} | |
static void noop_handler(int signo, siginfo_t* siginfo, void* ucontext) { | |
} | |
__attribute__((visibility("default"))) | |
int Agent_OnLoad(void* vm, char* options, void* reserved) { | |
struct sigaction sa; | |
sigemptyset(&sa.sa_mask); | |
sa.sa_sigaction = noop_handler; | |
sa.sa_flags = SA_SIGINFO | SA_RESTART; | |
sigaction(SIGPROF, &sa, NULL); | |
pthread_t thread; | |
if (pthread_create(&thread, NULL, signaling_loop, NULL) == 0) { | |
printf("Signaler started\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment