Skip to content

Commit

Permalink
feat: Allow longer java symbol name
Browse files Browse the repository at this point in the history
  • Loading branch information
rvql authored and sharang committed Jul 29, 2024
1 parent b3a39e5 commit b76c34f
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 29 deletions.
10 changes: 9 additions & 1 deletion agent/src/ebpf/kernel/include/perf_profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ typedef enum {
PROFILER_CNT
} profiler_idx;

#define JAVA_SYMBOL_MAX_LENGTH 128
#define MAP_MEMORY_JAVA_SYMBOL_MAP_NAME "__memory_java_symbol_map"

struct java_symbol_map_key {
__u32 tgid;
__u64 class_id;
};

struct stack_trace_key_t {
__u32 pid; // processID or threadID
__u32 tgid; // processID
Expand All @@ -56,7 +64,7 @@ struct stack_trace_key_t {
} off_cpu;
struct {
__u64 size;
char class_name[32]; // TODO: change to a symbol id
__u64 class_id; // Use symbol address as class_id
} memory;
} ext_data;
};
Expand Down
47 changes: 43 additions & 4 deletions agent/src/ebpf/user/profile/profile_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,27 @@ static inline void update_matched_process_in_total(struct profiler_context *ctx,
}
}

#define UNKNOWN_JAVA_SYMBOL_STR "Unknown"

static char *get_java_symbol(struct bpf_tracer *t, struct java_symbol_map_key *key) {
char value[JAVA_SYMBOL_MAX_LENGTH];
memset(value, 0, JAVA_SYMBOL_MAX_LENGTH * sizeof(char));
if (!bpf_table_get(t, MAP_MEMORY_JAVA_SYMBOL_MAP_NAME, key, value)) {
return NULL;
}
char *ret = rewrite_java_symbol(value);
if (!ret) {
int len = strlen(value);
ret = clib_mem_alloc_aligned("symbol_str", len + 1, 0, NULL);
if (ret == NULL) {
return NULL;
}
memcpy(ret, value, len);
ret[len] = '\0';
}
return ret;
}

static void aggregate_stack_traces(struct profiler_context *ctx,
struct bpf_tracer *t,
const char *stack_map_name,
Expand Down Expand Up @@ -913,9 +934,18 @@ static void aggregate_stack_traces(struct profiler_context *ctx,
if (matched)
str_len += strlen(v->comm) + sizeof(pre_tag);

if (ctx->type == PROFILER_TYPE_MEMORY) {
rewrite_java_symbol(v->ext_data.memory.class_name);
str_len += strlen(v->ext_data.memory.class_name) + 1;
char *class_name = NULL;

if (ctx->type == PROFILER_TYPE_MEMORY && v->ext_data.memory.class_id != 0) {
struct java_symbol_map_key key = { 0 };
key.tgid = v->tgid;
key.class_id = v->ext_data.memory.class_id;
class_name = get_java_symbol(t, &key);
if (class_name) {
str_len += strlen(class_name) + 1;
} else {
str_len += strlen(UNKNOWN_JAVA_SYMBOL_STR) + 1;
}
}

int len = sizeof(stack_trace_msg_t) + str_len;
Expand All @@ -924,6 +954,9 @@ static void aggregate_stack_traces(struct profiler_context *ctx,
clib_mem_free(trace_str);
if (__info_p)
AO_DEC(&__info_p->use);
if (class_name) {
clib_mem_free(class_name);
}
continue;
}

Expand All @@ -943,7 +976,13 @@ static void aggregate_stack_traces(struct profiler_context *ctx,
}
offset += snprintf(msg_str + offset, str_len - offset, "%s", trace_str);
if (ctx->type == PROFILER_TYPE_MEMORY) {
offset += snprintf(msg_str + offset, str_len - offset, ";%s", v->ext_data.memory.class_name);
if (class_name) {
offset += snprintf(msg_str + offset, str_len - offset, ";%s", class_name);
clib_mem_free(class_name);
class_name = NULL;
} else {
offset += snprintf(msg_str + offset, str_len - offset, ";%s", UNKNOWN_JAVA_SYMBOL_STR);
}
}

msg->data_len = strlen((char *)msg->data);
Expand Down
98 changes: 75 additions & 23 deletions agent/src/ebpf/user/profile/stringifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,42 +194,90 @@ static char *proc_symbol_name_fetch(pid_t pid, struct bcc_symbol *sym)
return ptr;
}

void rewrite_java_symbol(char *sym) {
// Demangle with
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3
char *rewrite_java_symbol(char *sym) {
int len = strlen(sym);
if (len == 0) {
return;
return NULL;
}

int i, cls_start = 1;
bool is_array = false;
int i = 0, j = 0;
for (i = 0; i < len && sym[i] == '['; i++) {}
int array_dims = i;

switch (sym[0]) {
case '[':
if (len <= 1 || sym[1] != 'L') {
break;
}
is_array = true;
cls_start++;
// fallthrough to handle "[LClassname;::methodName"
// make room for array ']'s and base type name expension
int new_len = len + array_dims + 16;
char *dst = clib_mem_alloc_aligned("symbol_str", new_len, 0, NULL);
if (dst == NULL) {
return dst;
}
memset(dst, 0, new_len);
int offset = 0;

switch (sym[i]) {
case 'B':
offset += snprintf(dst + offset, new_len - offset, "byte");
i++;
break;
case 'C':
offset += snprintf(dst + offset, new_len - offset, "char");
i++;
break;
case 'D':
offset += snprintf(dst + offset, new_len - offset, "double");
i++;
break;
case 'F':
offset += snprintf(dst + offset, new_len - offset, "float");
i++;
break;
case 'I':
offset += snprintf(dst + offset, new_len - offset, "int");
i++;
break;
case 'J':
offset += snprintf(dst + offset, new_len - offset, "long");
i++;
break;
case 'S':
offset += snprintf(dst + offset, new_len - offset, "short");
i++;
break;
case 'Z':
offset += snprintf(dst + offset, new_len - offset, "boolean");
i++;
break;
case 'L':
// LClassName;::methodName
for (i = cls_start; i < len; i++) {
if (sym[i] == ';') {
for (j = i + 1; j < len; j++) {
if (sym[j] == ';') {
break;
}
}
if (i != len) {
memcpy(sym, sym + cls_start, i - cls_start);
memcpy(sym + i - cls_start, sym + i + 1, len - i - 1);
memset(sym + len - cls_start - 1, '\0', cls_start + 1);
if (is_array) {
memcpy(sym + len - cls_start - 1, "[]", 2);
}
if (j == len) {
goto failed;
}
memcpy(dst + offset, sym + i + 1, j - (i + 1));
offset += j - i;
i = j + 1;
break;
default:
break;
goto failed;
}

for (int j = 0; j < array_dims; j++) {
offset += snprintf(dst + offset, new_len - offset, "[]");
}

// rest
snprintf(dst + offset, new_len - offset, sym + i);

return dst;

failed:
clib_mem_free(dst);
return NULL;
}

static inline int symcache_resolve(pid_t pid, void *resolver, u64 address,
Expand All @@ -255,7 +303,11 @@ static inline int symcache_resolve(pid_t pid, void *resolver, u64 address,
*sym_ptr = proc_symbol_name_fetch(pid, sym);
if (p->is_java) {
// handle java encoded symbols
rewrite_java_symbol(*sym_ptr);
char *new_sym = rewrite_java_symbol(*sym_ptr);
if (new_sym != NULL) {
clib_mem_free(*sym_ptr);
*sym_ptr = new_sym;
}
}
pthread_mutex_unlock(&p->mutex);
return ret;
Expand Down
2 changes: 1 addition & 1 deletion agent/src/ebpf/user/profile/stringifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ char *resolve_and_gen_stack_trace_str(struct bpf_tracer *t,
stack_str_hash_t *h,
bool new_cache,
char *process_name, void *info_p, bool ignore_libs);
void rewrite_java_symbol(char *sym);
char *rewrite_java_symbol(char *sym);

#endif /* AARCH64_MUSL */
#endif /* DF_USER_STRINGIFIER_H */
15 changes: 15 additions & 0 deletions agent/src/ebpf/user/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@
#include "table.h"
#include "log.h"

bool bpf_table_get(struct bpf_tracer *tracer,
const char *tb_name, void *key, void *val)
{
struct ebpf_map *map = ebpf_obj__get_map_by_name(tracer->obj, tb_name);
if (map == NULL) {
ebpf_warning("[%s] map name \"%s\" map is NULL.\n", __func__,
tb_name);
return false;
}

int map_fd = map->fd;

return bpf_lookup_elem(map_fd, key, val) == 0;
}

bool bpf_table_get_value(struct bpf_tracer *tracer,
const char *tb_name, uint64_t key, void *val_buf)
{
Expand Down
3 changes: 3 additions & 0 deletions agent/src/ebpf/user/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#define DF_BPF_TABLE_H
#include "tracer.h"

bool bpf_table_get(struct bpf_tracer *tracer,
const char *tb_name, void *key, void *val);

bool bpf_table_get_value(struct bpf_tracer *tracer,
const char *tb_name,
uint64_t key,
Expand Down

0 comments on commit b76c34f

Please sign in to comment.