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
240 changes: 200 additions & 40 deletions agent/Cargo.lock

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ cloud_platform = { path = "plugins/cloud_platform" }
dashmap = "5.3.3"
dns-lookup = "1.0.8"
elf = "0.4.0"
enum_dispatch = "0.3.7"
enterprise-utils = { path = "crates/enterprise-utils", optional = true }
enum_dispatch = "0.3.7"
envmnt = "0.10.4"
flate2 = "1.0.23"
# the feature flag fixes the following problem:
#
Expand Down Expand Up @@ -86,7 +87,7 @@ thiserror = "1.0"
time = "0.3.9"
tokio = { version = "1.20.1", features = ["full"] }
tonic = "0.8.1"
envmnt = "0.10.4"
trace-utils = { path = "crates/trace-utils" }
wasmtime = "12.0.1"
wasmtime-wasi = "12.0.1"

Expand Down
19 changes: 19 additions & 0 deletions agent/crates/trace-utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "trace-utils"
version = "0.1.0"
edition = "2021"

[dependencies]
ahash = "0.8"
gimli = "0.31"
libc = "0.2"
log = "0.4"
object = "0.36"
rustc-demangle = "0.1"
thiserror = "1.0"

[build-dependencies]
cc = "1.0"

[dev-dependencies]
env_logger = "0.11"
20 changes: 20 additions & 0 deletions agent/crates/trace-utils/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

fn main() {
cc::Build::new().file("src/bpf.c").compile("dummy");
println!("cargo:rerun-if-changed=src/bpf.c");
}
69 changes: 69 additions & 0 deletions agent/crates/trace-utils/cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
################################################################################
# #
# Copyright (c) 2024 Yunshan Networks #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
# #
################################################################################

language = "C"

header = """
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/"""
include_guard = "TRACE_UTILS_H"
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
sys_includes = ["stdint.h"]
no_includes = true

#### code style ####
line_length = 100
tab_width = 4
line_endings = "LF"

#### codegen options ####
style = "type"
sort_by = "Name"
usize_is_size_t = true

[export]
include = ["ProcessShardList", "UnwindEntryShard"]
exclude = ["bpf_update_elem", "bpf_delete_elem"]
item_types = []
renaming_overrides_prefixing = false

[export.rename]
ShardInfo = "shard_info_t"
ProcessShardList = "process_shard_list_t"
UnwindEntry = "unwind_entry_t"
UnwindEntryShard = "unwind_entry_shard_t"
UnwindTable = "unwind_table_t"

[struct]
rename_fields = "SnakeCase"

[enum]
rename_variants = "QualifiedScreamingSnakeCase"
13 changes: 13 additions & 0 deletions agent/crates/trace-utils/examples/unwind_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use trace_utils::unwind::dwarf::read_unwind_entries;

use std::fs;

use log::info;

fn main() {
env_logger::init();
let filename = std::env::args().nth(1).unwrap();
info!("read {filename}");
let contents = fs::read(filename).unwrap();
read_unwind_entries(&contents);
}
39 changes: 39 additions & 0 deletions agent/crates/trace-utils/src/bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* Phony functions to make examples in this crate work
* Linking with libbpf will replace these weak symbols
*/

#include <stdint.h>

#define UNUSED(x) (void)(x)

int __attribute__((weak))
bpf_update_elem(int fd, const void *key, const void *value, uint64_t flags) {
UNUSED(fd);
UNUSED(key);
UNUSED(value);
UNUSED(flags);
return 0;
}

int __attribute__((weak)) bpf_delete_elem(int fd, const void *key) {
UNUSED(fd);
UNUSED(key);
return 0;
}
31 changes: 31 additions & 0 deletions agent/crates/trace-utils/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
#[error(transparent)]
FileReadError(#[from] std::io::Error),
#[error(transparent)]
ElfReadError(#[from] object::Error),
#[error(transparent)]
ElfParseError(#[from] gimli::Error),
#[error(".eh_frame section not found in object file")]
NoEhFrame,
}

pub type Result<T> = std::result::Result<T, Error>;
86 changes: 86 additions & 0 deletions agent/crates/trace-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

pub mod error;
pub mod unwind;

use std::io::Write;

use unwind::UnwindTable;

#[no_mangle]
pub unsafe extern "C" fn unwind_table_create(
process_shard_list_map_fd: i32,
unwind_entry_shard_map_fd: i32,
) -> *mut UnwindTable {
let table = Box::new(UnwindTable::new(
process_shard_list_map_fd,
unwind_entry_shard_map_fd,
));
Box::into_raw(table)
}

#[no_mangle]
pub unsafe extern "C" fn unwind_table_destroy(table: *mut UnwindTable) {
if table.is_null() {
return;
}
std::mem::drop(Box::from_raw(table));
}

#[no_mangle]
pub unsafe extern "C" fn unwind_table_load(table: *mut UnwindTable, pid: u32) {
(*table).load(pid);
}

#[no_mangle]
pub unsafe extern "C" fn unwind_table_unload(table: *mut UnwindTable, pid: u32) {
(*table).unload(pid);
}

#[no_mangle]
pub unsafe extern "C" fn unwind_table_unload_all(table: *mut UnwindTable) {
(*table).unload_all();
}

#[no_mangle]
pub unsafe extern "C" fn frame_pointer_heuristic_check(pid: u32) -> bool {
unwind::dwarf::frame_pointer_heuristic_check(pid)
}

// forwards rust demangle to C api
// The code is from: https://github.com/rust-lang/rustc-demangle/blob/main/crates/capi/src/lib.rs
#[no_mangle]
pub unsafe extern "C" fn rustc_demangle(
mangled: *const libc::c_char,
out: *mut libc::c_char,
out_size: usize,
) -> libc::c_int {
let mangled_str = match std::ffi::CStr::from_ptr(mangled).to_str() {
Ok(s) => s,
Err(_) => return 0,
};
match rustc_demangle::try_demangle(mangled_str) {
Ok(demangle) => {
let mut out_slice = std::slice::from_raw_parts_mut(out as *mut u8, out_size);
match write!(out_slice, "{:#}\0", demangle) {
Ok(_) => return 1,
Err(_) => return 0,
}
}
Err(_) => return 0,
}
}
90 changes: 90 additions & 0 deletions agent/crates/trace-utils/src/trace_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef TRACE_UTILS_H
#define TRACE_UTILS_H

/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */

#include <stdint.h>

#define UNWIND_ENTRIES_PER_SHARD 65535

#define UNWIND_SHARDS_PER_PROCESS 256

enum CfaType {
CFA_TYPE_RBP_OFFSET,
CFA_TYPE_RSP_OFFSET,
CFA_TYPE_EXPRESSION,
CFA_TYPE_UNSUPPORTED,
CFA_TYPE_NO_ENTRY,
};
typedef uint8_t CfaType;

enum RegType {
REG_TYPE_UNDEFINED,
REG_TYPE_SAME_VALUE,
REG_TYPE_OFFSET,
REG_TYPE_UNSUPPORTED,
};
typedef uint8_t RegType;

typedef struct unwind_table_t unwind_table_t;

typedef struct {
uint32_t id;
uint64_t offset;
uint64_t pc_min;
uint64_t pc_max;
uint32_t entry_start;
uint32_t entry_end;
} shard_info_t;

typedef struct {
uint8_t len;
shard_info_t entries[UNWIND_SHARDS_PER_PROCESS];
} process_shard_list_t;

typedef struct {
uint64_t pc;
CfaType cfa_type;
RegType rbp_type;
int16_t cfa_offset;
int16_t rbp_offset;
} unwind_entry_t;

typedef struct {
uint32_t id;
uint32_t len;
unwind_entry_t entries[UNWIND_ENTRIES_PER_SHARD];
} unwind_entry_shard_t;

bool frame_pointer_heuristic_check(uint32_t pid);

int rustc_demangle(const char *mangled, char *out, size_t out_size);

unwind_table_t *unwind_table_create(int32_t process_shard_list_map_fd,
int32_t unwind_entry_shard_map_fd);

void unwind_table_destroy(unwind_table_t *table);

void unwind_table_load(unwind_table_t *table, uint32_t pid);

void unwind_table_unload(unwind_table_t *table, uint32_t pid);

void unwind_table_unload_all(unwind_table_t *table);

#endif /* TRACE_UTILS_H */
Loading