Skip to content
Open
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
49 changes: 48 additions & 1 deletion agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ kube = { version = "0.98", default-features = false }
prost = "0.12"
public = { path = "crates/public" }
regex = "1"
semver = { version = "1.0", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
# why tonic 0.10:
# - tonic >= 0.11 uses tokio-rustls 0.25 that no longer allow disabling certificate verifier
Expand Down
4 changes: 4 additions & 0 deletions agent/crates/trace-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name = "trace-utils"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["rlib", "staticlib"]

[dependencies]
ahash = "0.8"
btf-rs = "1.1"
Expand All @@ -23,3 +26,4 @@ cc = "1.0"

[dev-dependencies]
env_logger = "0.11"
tempfile = "3.0"
6 changes: 6 additions & 0 deletions agent/crates/trace-utils/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ pub enum Error {
BadInterpreterType(u32, &'static str),
#[error("Process#{0} {1} v{2} not supported")]
BadInterpreterVersion(u32, &'static str, Version),
#[error("Process#{0} not found or not accessible")]
ProcessNotFound(u32),
#[error("Invalid pointer address: 0x{0:x}")]
InvalidPointer(u64),
#[error("Invalid or corrupted data")]
InvalidData,
}

pub type Result<T> = std::result::Result<T, Error>;
54 changes: 53 additions & 1 deletion agent/crates/trace-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::io::Write;
use log::info;

// Crate internal modules
use unwind::{python::PythonUnwindTable, UnwindTable};
use unwind::{php::PhpUnwindTable, python::PythonUnwindTable, v8::V8UnwindTable, UnwindTable};
pub use utils::protect_cpu_affinity;

#[no_mangle]
Expand Down Expand Up @@ -96,6 +96,58 @@ pub unsafe extern "C" fn python_unwind_table_unload(table: *mut PythonUnwindTabl
(*table).unload(pid);
}

#[no_mangle]
pub unsafe extern "C" fn php_unwind_table_create(
unwind_info_map_fd: i32,
offsets_map_fd: i32,
) -> *mut PhpUnwindTable {
let table = Box::new(PhpUnwindTable::new(unwind_info_map_fd, offsets_map_fd));
Box::into_raw(table)
}

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

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

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

#[no_mangle]
pub unsafe extern "C" fn v8_unwind_table_create(
unwind_info_map_fd: i32,
offsets_map_fd: i32,
) -> *mut V8UnwindTable {
let table = Box::new(V8UnwindTable::new(unwind_info_map_fd, offsets_map_fd));
Box::into_raw(table)
}

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

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

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

// TODO: 暴露 lua 剖析相关函数给 C 部分

// forwards rust demangle to C api
Expand Down
15 changes: 15 additions & 0 deletions agent/crates/trace-utils/src/maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ pub fn get_memory_mappings(pid: u32) -> io::Result<Vec<MemoryArea>> {
trace!("found {:?}", la);
areas.push(la);
}

// CRITICAL FIX: Filter out dangerous device files to prevent infinite memory consumption
// Skip device files like /dev/zero, /dev/null, etc. that can cause OOM when read
if path.starts_with("/dev/zero")
|| path.starts_with("/dev/null")
|| path.starts_with("/dev/random")
|| path.starts_with("/dev/urandom")
|| path.contains("/dev/zero")
|| path.contains("/dev/null")
{
trace!("Skipping dangerous device file mapping: {}", path);
last_executable = false;
continue;
}

last_area.replace(MemoryArea {
m_start,
mx_start: if perms.contains('x') { m_start } else { 0 },
Expand Down
128 changes: 128 additions & 0 deletions agent/crates/trace-utils/src/trace_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ typedef struct {
uint8_t offsets_id;
} python_unwind_info_t;

typedef struct {
uint64_t executor_globals_address;
uint64_t jit_return_address;
uint64_t execute_ex_start; // absolute address of execute_ex start
uint64_t execute_ex_end; // absolute address of execute_ex end (exclusive)
uint8_t offsets_id;
uint8_t has_jit;
uint8_t _reserved[6];
} php_unwind_info_t;

typedef struct {
int64_t current_frame;
} py_cframe_t;
Expand Down Expand Up @@ -150,14 +160,110 @@ typedef struct {
py_type_object_t type_object;
} python_offsets_t;

typedef struct {
uint16_t current_execute_data;
} php_executor_globals_t;

typedef struct {
uint8_t opline;
uint8_t function;
uint8_t this_type_info;
uint8_t prev_execute_data;
} php_execute_data_t;

typedef struct {
uint8_t common_type;
uint8_t common_funcname;
uint8_t common_scope;
uint32_t op_array_filename;
uint32_t op_array_linestart;
uint32_t sizeof_struct;
} php_function_t;

typedef struct {
uint64_t val;
} php_string_t;

typedef struct {
uint8_t lineno;
} php_op_t;

typedef struct {
uint64_t name;
} php_class_entry_t;

typedef struct {
php_executor_globals_t executor_globals;
php_execute_data_t execute_data;
php_function_t function;
php_string_t string;
php_op_t op;
php_class_entry_t class_entry;
} php_offsets_t;

typedef struct {
uint64_t isolate_address;
uint8_t offsets_id;
uint32_t version;
} v8_unwind_info_t;

typedef struct {
int16_t marker;
int16_t function;
int16_t bytecode_offset;
} v8_frame_pointers_t;

typedef struct {
uint16_t shared;
uint16_t code;
} v8_js_function_t;

typedef struct {
uint16_t name_or_scope_info;
uint16_t function_data;
uint16_t script_or_debug_info;
} v8_shared_function_info_t;

typedef struct {
uint16_t instruction_start;
uint16_t instruction_size;
uint16_t flags;
} v8_code_t;

typedef struct {
uint16_t name;
uint16_t source;
} v8_script_t;

typedef struct {
uint16_t source_position_table;
} v8_bytecode_array_t;

typedef struct {
v8_frame_pointers_t frame_pointers;
v8_js_function_t js_function;
v8_shared_function_info_t shared_function_info;
v8_code_t code;
v8_script_t script;
v8_bytecode_array_t bytecode_array;
} v8_offsets_t;

bool frame_pointer_heuristic_check(uint32_t pid);

bool is_lua_process(uint32_t pid);

bool is_python_process(uint32_t pid);

bool is_php_process(uint32_t pid);

bool is_v8_process(uint32_t pid);

size_t merge_python_stacks(void *trace_str, size_t len, const void *i_trace, const void *u_trace);

size_t merge_php_stacks(void *trace_str, size_t len, const void *i_trace, const void *u_trace);

size_t merge_v8_stacks(void *trace_str, size_t len, const void *i_trace, const void *u_trace);

python_unwind_table_t *python_unwind_table_create(int32_t unwind_info_map_fd,
int32_t offsets_map_fd);

Expand All @@ -167,6 +273,28 @@ void python_unwind_table_load(python_unwind_table_t *table, uint32_t pid);

void python_unwind_table_unload(python_unwind_table_t *table, uint32_t pid);

typedef struct php_unwind_table_t php_unwind_table_t;

php_unwind_table_t *php_unwind_table_create(int32_t unwind_info_map_fd,
int32_t offsets_map_fd);

void php_unwind_table_destroy(php_unwind_table_t *table);

void php_unwind_table_load(php_unwind_table_t *table, uint32_t pid);

void php_unwind_table_unload(php_unwind_table_t *table, uint32_t pid);

typedef struct v8_unwind_table_t v8_unwind_table_t;

v8_unwind_table_t *v8_unwind_table_create(int32_t unwind_info_map_fd,
int32_t offsets_map_fd);

void v8_unwind_table_destroy(v8_unwind_table_t *table);

void v8_unwind_table_load(v8_unwind_table_t *table, uint32_t pid);

void v8_unwind_table_unload(v8_unwind_table_t *table, uint32_t pid);

int32_t read_offset_of_stack_in_task_struct(void);

int rustc_demangle(const char *mangled, char *out, size_t out_size);
Expand Down
4 changes: 4 additions & 0 deletions agent/crates/trace-utils/src/unwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@

pub mod dwarf;
pub mod lua;
pub mod php;
pub mod php_jit;
pub mod php_opcache;
pub mod python;
pub mod v8;

use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
use std::collections::{hash_map::Entry, HashMap, HashSet};
Expand Down
3 changes: 2 additions & 1 deletion agent/crates/trace-utils/src/unwind/lua.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@
#[no_mangle]
pub unsafe extern "C" fn is_lua_process(_: u32) -> bool {
// TODO: 判断是否是 lua/nginx 进程
todo!()
// 暂时返回 false,避免 todo!() 宏 panic 导致程序崩溃
false
}
Loading