ghostscope_compiler/
lib.rs1pub mod ebpf;
5pub mod script; use crate::script::compiler::AstCompiler;
11use ebpf::context::CodeGenError;
12use script::parser::ParseError;
13use tracing::info;
14
15pub fn hello() -> &'static str {
16 "Hello from ghostscope-compiler!"
17}
18
19#[derive(Debug, thiserror::Error)]
20pub enum CompileError {
21 #[error("Parse error: {0}")]
22 Parse(#[from] Box<ParseError>),
23
24 #[error("Code generation error: {0}")]
25 CodeGen(#[from] CodeGenError),
26
27 #[error("LLVM error: {0}")]
28 LLVM(String),
29
30 #[error("{0}")]
31 Other(String),
32}
33
34pub type Result<T> = std::result::Result<T, CompileError>;
35
36impl From<ParseError> for CompileError {
37 fn from(err: ParseError) -> Self {
38 CompileError::Parse(Box::new(err))
39 }
40}
41
42pub use script::compiler::{CompilationResult, UProbeConfig};
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum EventMapType {
48 RingBuf,
50 PerfEventArray,
52}
53
54#[derive(Debug, Clone)]
56pub struct CompileOptions {
57 pub save_llvm_ir: bool,
58 pub save_ebpf: bool,
59 pub save_ast: bool,
60 pub binary_path_hint: Option<String>,
61 pub ringbuf_size: u64,
62 pub proc_module_offsets_max_entries: u64,
63 pub perf_page_count: u32,
64 pub event_map_type: EventMapType,
65 pub mem_dump_cap: u32,
67 pub compare_cap: u32,
69 pub max_trace_event_size: u32,
71 pub selected_index: Option<usize>,
74}
75
76impl Default for CompileOptions {
77 fn default() -> Self {
78 Self {
79 save_llvm_ir: false,
80 save_ebpf: false,
81 save_ast: false,
82 binary_path_hint: None,
83 ringbuf_size: 262144, proc_module_offsets_max_entries: 4096, perf_page_count: 64, event_map_type: EventMapType::RingBuf, mem_dump_cap: 4096, compare_cap: 64, max_trace_event_size: 32768, selected_index: None,
91 }
92 }
93}
94
95pub fn compile_script(
100 script_source: &str,
101 process_analyzer: &mut ghostscope_dwarf::DwarfAnalyzer,
102 pid: Option<u32>,
103 trace_id: Option<u32>,
104 compile_options: &CompileOptions,
105) -> Result<CompilationResult> {
106 info!("Starting unified script compilation with DwarfAnalyzer (multi-module support)");
107
108 let program = script::parser::parse(script_source)?;
110 info!("Parsed script with {} statements", program.statements.len());
111
112 let mut compiler = AstCompiler::new(
114 Some(process_analyzer),
115 compile_options.binary_path_hint.clone(),
116 trace_id.unwrap_or(0), compile_options.clone(),
118 );
119
120 let result = compiler.compile_program(&program, pid)?;
122
123 if result.uprobe_configs.is_empty() {
124 if !result.failed_targets.is_empty() {
125 tracing::warn!(
126 "Compilation produced 0 uprobe configs; {} target(s) failed to compile",
127 result.failed_targets.len()
128 );
129 } else {
130 tracing::warn!(
131 "Compilation completed with 0 uprobe configs (no attachable targets resolved)"
132 );
133 }
134 } else {
135 info!(
136 "Successfully compiled script: {} trace points, {} uprobe configs",
137 result.trace_count,
138 result.uprobe_configs.len()
139 );
140 }
141
142 info!(
144 "Compilation summary: trace_points={}, uprobe_configs={}, failed_targets={}",
145 result.trace_count,
146 result.uprobe_configs.len(),
147 result.failed_targets.len()
148 );
149
150 Ok(result)
151}
152
153pub fn print_ast(program: &crate::script::Program) {
155 info!("\n=== AST Tree ===");
156 info!("Program:");
157 for (i, stmt) in program.statements.iter().enumerate() {
158 info!(" Statement {}: {:?}", i, stmt);
159 }
160 info!("=== End AST Tree ===\n");
161}
162
163pub fn save_ast_to_file(program: &crate::script::Program, filename: &str) -> Result<()> {
165 let mut ast_content = String::new();
166 ast_content.push_str("=== AST Tree ===\n");
167 ast_content.push_str("Program:\n");
168 for (i, stmt) in program.statements.iter().enumerate() {
169 ast_content.push_str(&format!(" Statement {i}: {stmt:?}\n"));
170 }
171 ast_content.push_str("=== End AST Tree ===\n");
172
173 let file_path = format!("{filename}.txt");
174 std::fs::write(&file_path, ast_content)
175 .map_err(|e| CompileError::Other(format!("Failed to save AST file '{file_path}': {e}")))?;
176
177 Ok(())
178}
179
180pub fn format_ebpf_bytecode(bytecode: &[u8]) -> String {
182 bytecode
183 .iter()
184 .map(|byte| format!("{byte:02x}"))
185 .collect::<Vec<String>>()
186 .join(" ")
187}
188
189pub fn generate_file_name_for_ast(pid: Option<u32>, binary_path: Option<&str>) -> String {
191 let pid_part = pid
192 .map(|p| p.to_string())
193 .unwrap_or_else(|| "unknown".to_string());
194 let exec_part = binary_path
195 .and_then(|path| std::path::Path::new(path).file_name())
196 .and_then(|name| name.to_str())
197 .unwrap_or("unknown");
198
199 format!("gs_{pid_part}_{exec_part}_ast")
200}