mod cli;
mod config;
mod core;
mod logging;
mod runtime;
mod script;
mod tracing;
mod util;
use anyhow::Result;
use ::tracing::{info, warn};
use libc as c;
#[tokio::main]
async fn main() -> Result<()> {
crate::util::setup_panic_hook();
let _ = ghostscope_process::maps::cleanup_pinned_proc_offsets();
let parsed_args = config::Args::parse_args();
let config_path = parsed_args.config.clone();
let merged_config =
match config::MergedConfig::new_with_explicit_config(parsed_args, config_path) {
Ok(config) => config,
Err(e) => {
eprintln!("❌ Configuration Error:\n{e}");
eprintln!("\n💡 Tips:");
eprintln!(" • Check the example config.toml in the project root");
eprintln!(" • Verify TOML syntax is correct");
eprintln!(" • Ensure all values use the correct format");
std::process::exit(1);
}
};
let log_file_string = merged_config.log_file.to_string_lossy().to_string();
let log_file_path = Some(log_file_string.as_str());
if let Err(e) = logging::initialize_logging_with_config(
log_file_path,
merged_config.enable_logging,
merged_config.enable_console_logging,
merged_config.log_level,
merged_config.tui_mode,
) {
eprintln!("Failed to initialize logging: {e}");
return Err(anyhow::anyhow!("Failed to initialize logging: {}", e));
}
unsafe {
c::atexit(crate::util::cleanup_pinned_maps_on_exit);
}
if let Some(config_path) = &merged_config.config_file_path {
info!("Configuration loaded from: {}", config_path.display());
} else {
let home_hint = std::env::var("HOME").unwrap_or_else(|_| "(unset)".into());
info!(
"Using built-in defaults (no config found at {}/.ghostscope/config.toml or ./ghostscope.toml)",
home_hint
);
}
crate::util::ensure_privileges();
if merged_config.ebpf_config.force_perf_event_array {
warn!("⚠️ TESTING MODE: force_perf_event_array=true - will use PerfEventArray");
info!("Skipping RingBuf detection, validating PerfEventArray support...");
match ghostscope_loader::KernelCapabilities::get_perf_only() {
Ok(kernel_caps) => {
info!("Kernel eBPF capabilities:");
info!(
" PerfEventArray support: {}",
kernel_caps.supports_perf_event_array
);
}
Err(err) => {
eprintln!("Error: {err}");
eprintln!("GhostScope requires Linux kernel >= 4.3 with PerfEventArray enabled.");
std::process::exit(1);
}
}
} else {
match ghostscope_loader::KernelCapabilities::get() {
Ok(kernel_caps) => {
info!("Kernel eBPF capabilities:");
info!(" RingBuf support: {}", kernel_caps.supports_ringbuf);
if !kernel_caps.supports_ringbuf {
warn!("⚠️ Kernel does not support RingBuf (requires >= 5.8)");
warn!("⚠️ GhostScope will use PerfEventArray as fallback");
}
}
Err(err) => {
eprintln!("Error: {err}");
eprintln!(
"GhostScope requires Linux kernel >= 4.3 with either RingBuf (>= 5.8) or PerfEventArray support."
);
eprintln!(
"Hint: ensure CONFIG_BPF, CONFIG_BPF_SYSCALL and CONFIG_UPROBE_EVENTS are enabled in your kernel."
);
std::process::exit(1);
}
}
}
let temp_args = config::ParsedArgs {
binary_path: merged_config.binary_path.clone(),
target_path: merged_config.target_path.clone(),
binary_args: merged_config.binary_args.clone(),
log_file: Some(merged_config.log_file.clone()),
enable_logging: merged_config.enable_logging,
enable_console_logging: merged_config.enable_console_logging,
log_level: merged_config.log_level,
config: None, debug_file: merged_config.debug_file.clone(),
script: merged_config.script.clone(),
script_file: merged_config.script_file.clone(),
pid: merged_config.pid,
tui_mode: merged_config.tui_mode,
should_save_llvm_ir: merged_config.should_save_llvm_ir,
should_save_ebpf: merged_config.should_save_ebpf,
should_save_ast: merged_config.should_save_ast,
layout_mode: merged_config.layout_mode,
has_explicit_log_flag: false, has_explicit_console_log_flag: false, force_perf_event_array: merged_config.ebpf_config.force_perf_event_array,
enable_sysmon_for_shared_lib: merged_config.ebpf_config.enable_sysmon_for_shared_lib,
allow_loose_debug_match: merged_config.dwarf_allow_loose_debug_match,
source_panel: false,
no_source_panel: false,
};
temp_args.validate()?;
if merged_config.tui_mode {
runtime::run_tui_coordinator_with_config(merged_config).await
} else {
cli::run_command_line_runtime_with_config(merged_config).await
}
}