Skip to content
This repository was archived by the owner on Jan 27, 2025. It is now read-only.

Commit b986697

Browse files
committed
feat: add JNI Interface Counter
1 parent 24dffb0 commit b986697

File tree

11 files changed

+319
-0
lines changed

11 files changed

+319
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include "declaration.h"
2+
3+
#include "runtime.h"
4+
5+
#ifndef NULL
6+
#define NULL 0
7+
#endif // NULL
8+
9+
void __foo() { __before_interface_call(NULL, NULL); }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef DECLARATION_H_
2+
#define DECLARATION_H_
3+
4+
void __foo();
5+
6+
#endif // DECLARATION_H_
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include "runtime.h"
2+
3+
#include <stddef.h>
4+
#include <stdio.h>
5+
#include <string.h>
6+
#include <time.h>
7+
8+
#include "../../common/dictionary.h"
9+
10+
#ifndef INTERFACE_COUNTER_PATH
11+
#define INTERFACE_COUNTER_PATH "/sdcard/interface-counter"
12+
#endif // INTERFACE_COUNTER_PATH
13+
14+
#ifndef FILENAME_CAPACITY
15+
#define FILENAME_CAPACITY 128
16+
#endif // FILENAME_CAPACITY
17+
18+
#ifndef SAVE_INTERVAL
19+
#define SAVE_INTERVAL 8
20+
#endif // SAVE_INTERVAL
21+
22+
#ifdef ANDROID
23+
#include <android/log.h>
24+
#define LOG_TAG "liblaf"
25+
#define ALOGV(...) \
26+
__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
27+
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
28+
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
29+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
30+
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
31+
#define ALOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__)
32+
#else
33+
#define ALOGV(...)
34+
#define ALOGD(...)
35+
#define ALOGI(...)
36+
#define ALOGW(...)
37+
#define ALOGE(...)
38+
#define ALOGF(...)
39+
#endif
40+
41+
DEFINE_DICTIONARY(Dict, const char*, int);
42+
43+
static void save_to_file();
44+
static void __attribute__((constructor(100))) runtime_init();
45+
static void __attribute__((destructor(100))) runtime_exit();
46+
47+
static FILE* file = NULL;
48+
static struct Dict* dict = NULL;
49+
static int counter = 0;
50+
51+
int Dict_cmp(const DictKeyType* a, const DictKeyType* b) {
52+
return strcmp(*a, *b);
53+
}
54+
55+
int Dict_hash(const DictKeyType* key) {
56+
int hash = 0;
57+
for (size_t n = strlen(*key), i = 0; i < n; i++) {
58+
hash = (hash << 5) | (hash >> 27);
59+
hash += (*key)[i];
60+
hash &= 0x7fffffff;
61+
}
62+
return hash;
63+
}
64+
65+
void Dict_key_copy(DictKeyType* dest, const DictKeyType* src) { *dest = *src; }
66+
67+
void Dict_value_copy(DictValueType* dest, const DictValueType* src) {
68+
*dest = *src;
69+
}
70+
71+
void __before_interface_call(const char* loc, const char* called_func_name) {
72+
int* value = Dict_get(dict, called_func_name);
73+
if (value) {
74+
++(*value);
75+
} else {
76+
Dict_put(dict, called_func_name, 1);
77+
}
78+
if (++counter >= SAVE_INTERVAL) {
79+
save_to_file();
80+
counter = 0;
81+
}
82+
}
83+
84+
static void save_to_file() {
85+
rewind(file);
86+
for (int i = 0; i < Dict_capacity(dict); ++i) {
87+
if (dict->_buckets[i]) {
88+
fprintf(file, "%s %d\n", dict->_buckets[i]->key,
89+
dict->_buckets[i]->value);
90+
}
91+
}
92+
fflush(file);
93+
}
94+
95+
static void runtime_init() {
96+
if (dict || file) return;
97+
dict = Dict_new(1000009);
98+
char filename[FILENAME_CAPACITY];
99+
sprintf(filename, "%s/%09ld.txt", INTERFACE_COUNTER_PATH, clock());
100+
file = fopen(filename, "w");
101+
ALOGI("runtime_init(%s)", filename);
102+
}
103+
104+
static void runtime_exit() {
105+
ALOGI("runtime_exit()");
106+
save_to_file();
107+
fclose(file);
108+
Dict_delete(dict);
109+
dict = NULL;
110+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef RUNTIME_H_
2+
#define RUNTIME_H_
3+
4+
void __before_interface_call(const char* loc, const char* called_func_name);
5+
6+
#endif // RUNTIME_H_

src/main/jni/interface_counter.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <memory>
2+
3+
#include "wrapper/jni/wrapper_interface_counter.h"
4+
5+
int main(int argc, char** argv) {
6+
auto wrapper = std::make_unique<WrapperInterfaceCounter>();
7+
int ret = wrapper->compile_c(argc, argv);
8+
return ret;
9+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include "pass_interface_counter.h"
2+
3+
#include "llvm/IR/IRBuilder.h"
4+
#include "llvm/IR/Instructions.h"
5+
#include "llvm/IR/Module.h"
6+
#include "pass/pass_call_hook.h"
7+
#include "utility/assertion.h"
8+
#include "utility/location.h"
9+
10+
using namespace llvm;
11+
12+
PassInterfaceCounter::PassInterfaceCounter(Module& target, Module& declaration)
13+
: PassCallHook(target, declaration), _interface_detector(target) {}
14+
15+
bool PassInterfaceCounter::run_on_call_inst(CallInst& inst) {
16+
assert_instruction_belong(inst, this->target());
17+
bool modified = false;
18+
if (this->interface_detector().is_interface_call(inst) == false)
19+
return modified;
20+
auto called_func_name = this->interface_detector().get_interface_name(inst);
21+
auto builder = IRBuilder<>(&inst);
22+
auto loc = builder.CreateGlobalStringPtr(get_inst_loc(inst));
23+
auto called_func_name_val = builder.CreateGlobalStringPtr(called_func_name);
24+
auto hook_func = this->target().getFunction(HOOK_NAME);
25+
auto hook_call = builder.CreateCall(hook_func, {loc, called_func_name_val});
26+
modified = true;
27+
assert(hook_call);
28+
return modified;
29+
}
30+
31+
JNIInterfaceDetector& PassInterfaceCounter::interface_detector() {
32+
return this->_interface_detector;
33+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef PASS_INTERFACE_COUNTER_H_
2+
#define PASS_INTERFACE_COUNTER_H_
3+
4+
#ifndef HOOK_NAME
5+
#define HOOK_NAME "__before_interface_call"
6+
#endif // HOOK_NAME
7+
8+
#include "llvm/IR/Module.h"
9+
#include "pass/pass_call_hook.h"
10+
#include "utility/jni/jni_interface_detector.h"
11+
12+
class PassInterfaceCounter : public PassCallHook {
13+
public:
14+
explicit PassInterfaceCounter(llvm::Module& target,
15+
llvm::Module& declaration);
16+
17+
virtual bool run_on_call_inst(llvm::CallInst& inst) override;
18+
19+
template <class PassType = PassInterfaceCounter>
20+
static bool apply_pass(llvm::StringRef target_ll,
21+
llvm::StringRef declaration_ll) {
22+
return PassCallHook::apply_pass<PassType>(target_ll, declaration_ll);
23+
}
24+
25+
protected:
26+
JNIInterfaceDetector& interface_detector();
27+
28+
private:
29+
JNIInterfaceDetector _interface_detector;
30+
};
31+
32+
#endif // PASS_INTERFACE_COUNTER_H_
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "jni_method_detector.h"
2+
3+
#include <cassert>
4+
5+
#include "llvm/IR/Function.h"
6+
#include "llvm/IR/Module.h"
7+
#include "utility/assertion.h"
8+
9+
using namespace llvm;
10+
11+
JNIMethodDetector::JNIMethodDetector(Module& target) : _target(target) {
12+
auto modified = this->run_on_module();
13+
assert(modified == false);
14+
}
15+
16+
bool JNIMethodDetector::is_dynamic_registered(llvm::Function& func) {
17+
if (!function_belong(func, this->target())) return false;
18+
// TODO
19+
return false;
20+
}
21+
22+
bool JNIMethodDetector::is_static_registered(llvm::Function& func) {
23+
if (!function_belong(func, this->target())) return false;
24+
// TODO
25+
return false;
26+
}
27+
28+
bool JNIMethodDetector::is_jni_method(Function& func) {
29+
return this->is_static_registered(func) || this->is_dynamic_registered(func);
30+
}
31+
32+
bool JNIMethodDetector::run_on_module() {
33+
bool modified = false;
34+
// TODO
35+
assert(modified == false);
36+
return modified;
37+
}
38+
39+
Module& JNIMethodDetector::target() { return this->_target; }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef JNI_METHOD_DETECTOR_H_
2+
#define JNI_METHOD_DETECTOR_H_
3+
4+
#include "llvm/IR/Function.h"
5+
#include "llvm/IR/Module.h"
6+
7+
class JNIMethodDetector {
8+
public:
9+
JNIMethodDetector(llvm::Module& target);
10+
11+
bool is_dynamic_registered(llvm::Function& func);
12+
bool is_static_registered(llvm::Function& func);
13+
bool is_jni_method(llvm::Function& func);
14+
15+
protected:
16+
bool run_on_module();
17+
llvm::Module& target();
18+
19+
private:
20+
llvm::Module& _target;
21+
};
22+
23+
#endif // JNI_METHOD_DETECTOR_H_
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "wrapper_interface_counter.h"
2+
3+
#include "common/arguments.h"
4+
#include "common/env.h"
5+
#include "common/logging.h"
6+
#include "common/path.h"
7+
#include "common/phase.h"
8+
#include "pass/jni/pass_interface_counter.h"
9+
10+
int WrapperInterfaceCounter::compile_s(Arguments args) {
11+
auto [phases, inputs, options] = this->prepare_args(args);
12+
13+
auto has_link_stage = Phase::has_link_stage(phases);
14+
auto declaration_c = get_env("DECLARATION_C", DECLARATION_C);
15+
auto declaration_ll = this->generate_ll(options, declaration_c);
16+
auto runtime_c = get_env("RUNTIME_C", RUNTIME_C);
17+
auto runtime_o = this->generate_o(options, runtime_c);
18+
19+
for (auto& input : inputs) {
20+
try {
21+
fs::path output = this->generate_ll(options, input);
22+
bool modified = PassInterfaceCounter::apply_pass(output.string(),
23+
declaration_ll.string());
24+
if (modified) input = output;
25+
} catch (const int e) {
26+
logger().error("{} => *.ll failed with exit code {}.", input, e);
27+
} catch (const std::exception& e) {
28+
logger().error("instrumentation failed: {}", e.what());
29+
}
30+
}
31+
32+
if (has_link_stage) inputs.push_back(runtime_o);
33+
args = this->join_args(options, inputs);
34+
int ret = this->exec_fork(args);
35+
return ret;
36+
}

0 commit comments

Comments
 (0)