Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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