blob: 3d087e5bb7b6139495714fa2a2e4b4496ffe6ada [file]
// Copyright 2025 The Pigweed Authors
//
// 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
//
// https://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 anyhow::Result;
mod image_info;
mod stacks;
mod trace;
use std::path::{Path, PathBuf};
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "k")]
#[command(about = "Pigweed Kernel CLI Tool", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Print information about a kernel image
#[command(name = "image_info")]
ImageInfo {
#[arg(required = true)]
path: PathBuf,
},
/// Print stack usage information from a running target
#[command(name = "stacks")]
Stacks {
#[arg(required = true)]
path: PathBuf,
#[arg(long, default_value = "localhost:1234")]
gdb: String,
},
/// Download a trace from a running target
#[command(name = "trace")]
Trace {
#[arg(required = true)]
path: PathBuf,
#[arg(long, default_value = "localhost:1234")]
gdb: String,
},
}
fn print_image_info(path: &Path) -> Result<()> {
let info = image_info::ImageInfo::new(path)?;
println!("Stacks:");
println!(" {:<30} {:<12} {:<10}", "Name", "Address", "Size");
println!(" {:-<30} {:-<12} {:-<10}", "", "", "");
for stack in info.stacks {
println!(
" {:<30} 0x{:08x} 0x{:x}",
stack.name, stack.stack_addr, stack.stack_size
);
}
println!();
println!("Threads:");
println!(" {:<30} {:<12} {:<12}", "Name", "Id", "Parent");
println!(" {:-<30} {:-<12} {:-<12}", "", "", "");
for thread in info.threads {
if thread.parent_id == 0x0 {
println!(" {:<30} 0x{:08x} kernel", thread.name, thread.id);
} else {
println!(
" {:<30} 0x{:08x} 0x{:08x}",
thread.name, thread.id, thread.parent_id
);
}
}
println!();
println!("Processes:");
println!(" {:<30} {:<12}", "Name", "Id");
println!(" {:-<30} {:-<12}", "", "");
for process in info.processes {
println!(" {:<30} 0x{:08x}", process.name, process.id);
}
println!();
println!("Trace Buffers:");
println!(" {:<30} {:<12} {:<10}", "Name", "Address", "Size");
println!(" {:-<30} {:-<12} {:-<10}", "", "", "");
for buffer in info.trace_buffers {
println!(
" {:<30} 0x{:08x} 0x{:x}",
buffer.name, buffer.addr, buffer.size
);
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
match &cli.command {
Commands::ImageInfo { path } => {
print_image_info(path)?;
}
Commands::Stacks { path, gdb } => {
stacks::run(path, gdb).await?;
}
Commands::Trace { path, gdb } => trace::run(path, gdb).await?,
}
Ok(())
}