mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 03:56:42 +00:00
OSDK GDB server args with QEMU-style options
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
43e3f8cf6b
commit
ab8b6afee5
5
Makefile
5
Makefile
@ -199,8 +199,7 @@ endif
|
||||
|
||||
.PHONY: gdb_server
|
||||
gdb_server: initramfs $(CARGO_OSDK)
|
||||
@cargo osdk run $(CARGO_OSDK_ARGS) --gdb-server --gdb-wait-client --gdb-vsc \
|
||||
--gdb-server-addr :$(GDB_TCP_PORT)
|
||||
@cargo osdk run $(CARGO_OSDK_ARGS) --gdb-server wait-client,vscode,addr=:$(GDB_TCP_PORT)
|
||||
|
||||
.PHONY: gdb_client
|
||||
gdb_client: $(CARGO_OSDK)
|
||||
@ -208,7 +207,7 @@ gdb_client: $(CARGO_OSDK)
|
||||
|
||||
.PHONY: profile_server
|
||||
profile_server: initramfs $(CARGO_OSDK)
|
||||
@cargo osdk run $(CARGO_OSDK_ARGS) --gdb-server --gdb-server-addr :$(GDB_TCP_PORT)
|
||||
@cargo osdk run $(CARGO_OSDK_ARGS) --gdb-server addr=:$(GDB_TCP_PORT)
|
||||
|
||||
.PHONY: profile_client
|
||||
profile_client: $(CARGO_OSDK)
|
||||
|
@ -15,16 +15,15 @@ Most options are the same as those of `cargo osdk build`.
|
||||
Refer to the [documentation](build.md) of `cargo osdk build`
|
||||
for more details.
|
||||
|
||||
Options related with debugging:
|
||||
Additionally, when running the kernel using QEMU, we can setup the QEMU as a
|
||||
debug server using option `--gdb-server`. This option supports an additional
|
||||
comma separated configuration list:
|
||||
|
||||
- `--gdb-server`: Enable QEMU GDB server for debugging.
|
||||
- `--gdb-wait-client`: Let the QEMU GDB server wait for the client connection before execution.
|
||||
- `--gdb-vsc`: Generate a '.vscode/launch.json' for debugging kernel with Visual Studio Code
|
||||
(only works when QEMU GDB server is enabled, i.e., `--gdb-server`).
|
||||
Requires [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb).
|
||||
- `--gdb-server-addr <ADDR>`: The network address on which the GDB server listens,
|
||||
it can be either a path for the UNIX domain socket or a TCP port on an IP address.
|
||||
[default: `.osdk-gdb-socket`(a local UNIX socket)]
|
||||
- `addr=ADDR`: the network or unix socket address on which the GDB server listens
|
||||
(default: `.osdk-gdb-socket`, a local UNIX socket);
|
||||
- `wait-client`: let the GDB server wait for the GDB client before execution;
|
||||
- `vscode`: generate a '.vscode/launch.json' for debugging with Visual Studio Code
|
||||
(Requires [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)).
|
||||
|
||||
See [Debug Command](debug.md) to interact with the GDB server in terminal.
|
||||
|
||||
@ -33,17 +32,17 @@ See [Debug Command](debug.md) to interact with the GDB server in terminal.
|
||||
Launch a debug server via QEMU with an unix socket stub, e.g. `.debug`:
|
||||
|
||||
```bash
|
||||
cargo osdk run --gdb-server --gdb-server-addr .debug
|
||||
cargo osdk run --gdb-server addr=.debug
|
||||
```
|
||||
|
||||
Launch a debug server via QEMU with a TCP stub, e.g., `localhost:1234`:
|
||||
|
||||
```bash
|
||||
cargo osdk run --gdb-server --gdb-server-addr :1234
|
||||
cargo osdk run --gdb-server addr=:1234
|
||||
```
|
||||
|
||||
Launch a debug server via QEMU and use VSCode to interact:
|
||||
Launch a debug server via QEMU and use VSCode to interact with:
|
||||
|
||||
```bash
|
||||
cargo osdk run --gdb-server --gdb-vsc --gdb-server-addr :1234
|
||||
cargo osdk run --gdb-server wait-client,vscode,addr=:1234
|
||||
```
|
||||
|
@ -37,7 +37,7 @@ pub fn main() {
|
||||
OsdkSubcommand::Run(run_args) => {
|
||||
execute_run_command(
|
||||
&load_config(&run_args.common_args),
|
||||
&run_args.gdb_server_args,
|
||||
run_args.gdb_server.as_deref(),
|
||||
);
|
||||
}
|
||||
OsdkSubcommand::Debug(debug_args) => {
|
||||
@ -168,44 +168,20 @@ pub struct BuildArgs {
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct RunArgs {
|
||||
#[command(flatten)]
|
||||
pub gdb_server_args: GdbServerArgs,
|
||||
#[command(flatten)]
|
||||
pub common_args: CommonArgs,
|
||||
}
|
||||
|
||||
#[derive(Debug, Args, Clone, Default)]
|
||||
pub struct GdbServerArgs {
|
||||
#[arg(
|
||||
long = "gdb-server",
|
||||
help = "Enable the QEMU GDB server for debugging",
|
||||
default_value_t
|
||||
help = "Enable the QEMU GDB server for debugging\n\
|
||||
This option supports an additional comma separated configuration list:\n\t \
|
||||
addr=ADDR: the network or unix socket address on which the GDB server listens, \
|
||||
`.osdk-gdb-socket` by default;\n\t \
|
||||
wait-client: let the GDB server wait for the GDB client before execution;\n\t \
|
||||
vscode: generate a '.vscode/launch.json' for debugging with Visual Studio Code.",
|
||||
value_name = "[addr=ADDR][,wait-client][,vscode]",
|
||||
default_missing_value = ""
|
||||
)]
|
||||
pub enabled: bool,
|
||||
#[arg(
|
||||
long = "gdb-wait-client",
|
||||
help = "Let the QEMU GDB server wait for the GDB client before execution",
|
||||
default_value_t,
|
||||
requires = "enabled"
|
||||
)]
|
||||
pub wait_client: bool,
|
||||
#[arg(
|
||||
long = "gdb-vsc",
|
||||
help = "Generate a '.vscode/launch.json' for debugging with Visual Studio Code \
|
||||
(only works when '--enable-gdb' is enabled)",
|
||||
default_value_t,
|
||||
requires = "enabled"
|
||||
)]
|
||||
pub vsc_launch_file: bool,
|
||||
#[arg(
|
||||
long = "gdb-server-addr",
|
||||
help = "The network address on which the GDB server listens, \
|
||||
it can be either a path for the UNIX domain socket or a TCP port on an IP address.",
|
||||
value_name = "ADDR",
|
||||
default_value = ".osdk-gdb-socket",
|
||||
requires = "enabled"
|
||||
)]
|
||||
pub host_addr: String,
|
||||
pub gdb_server: Option<String>,
|
||||
#[command(flatten)]
|
||||
pub common_args: CommonArgs,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -18,10 +18,9 @@ pub fn execute_debug_command(_profile: &str, args: &DebugArgs) {
|
||||
|
||||
let mut gdb = Command::new("gdb");
|
||||
gdb.args([
|
||||
format!("{}", file_path.display()).as_str(),
|
||||
"-ex",
|
||||
format!("target remote {}", remote).as_str(),
|
||||
"-ex",
|
||||
format!("file {}", file_path.display()).as_str(),
|
||||
]);
|
||||
gdb.status().unwrap();
|
||||
}
|
||||
|
@ -1,64 +1,29 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
use vsc::VscLaunchConfig;
|
||||
|
||||
use super::{build::create_base_and_cached_build, util::DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
cli::GdbServerArgs,
|
||||
config::{scheme::ActionChoice, Config},
|
||||
error::Errno,
|
||||
error_msg,
|
||||
util::{get_current_crate_info, get_target_directory},
|
||||
};
|
||||
|
||||
pub fn execute_run_command(config: &Config, gdb_server_args: &GdbServerArgs) {
|
||||
if gdb_server_args.enabled {
|
||||
use std::env;
|
||||
env::set_var(
|
||||
"RUSTFLAGS",
|
||||
env::var("RUSTFLAGS").unwrap_or_default() + " -g",
|
||||
);
|
||||
}
|
||||
|
||||
pub fn execute_run_command(config: &Config, gdb_server_args: Option<&str>) {
|
||||
let cargo_target_directory = get_target_directory();
|
||||
let osdk_output_directory = cargo_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let target_name = get_current_crate_info().name;
|
||||
|
||||
let mut config = config.clone();
|
||||
if gdb_server_args.enabled {
|
||||
let qemu_gdb_args = {
|
||||
let gdb_stub_addr = gdb_server_args.host_addr.as_str();
|
||||
match gdb::stub_type_of(gdb_stub_addr) {
|
||||
gdb::StubAddrType::Unix => {
|
||||
format!(
|
||||
" -chardev socket,path={},server=on,wait=off,id=gdb0 -gdb chardev:gdb0",
|
||||
gdb_stub_addr
|
||||
)
|
||||
}
|
||||
gdb::StubAddrType::Tcp => {
|
||||
format!(
|
||||
" -gdb tcp:{}",
|
||||
gdb::tcp_addr_util::format_tcp_addr(gdb_stub_addr)
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
config.run.qemu.args += &qemu_gdb_args;
|
||||
|
||||
if gdb_server_args.wait_client {
|
||||
config.run.qemu.args += " -S";
|
||||
}
|
||||
|
||||
// Ensure debug info added when debugging in the release profile.
|
||||
if config.run.build.profile.contains("release") {
|
||||
config
|
||||
.run
|
||||
.build
|
||||
.override_configs
|
||||
.push(format!("profile.{}.debug=true", config.run.build.profile));
|
||||
}
|
||||
}
|
||||
let _vsc_launch_file = gdb_server_args.vsc_launch_file.then(|| {
|
||||
vsc::check_gdb_config(gdb_server_args);
|
||||
let profile = super::util::profile_name_adapter(&config.run.build.profile);
|
||||
vsc::VscLaunchConfig::new(profile, &gdb_server_args.host_addr)
|
||||
});
|
||||
let _vsc_launch_file = if let Some(gdb_server_str) = gdb_server_args {
|
||||
adapt_for_gdb_server(&mut config, gdb_server_str)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let default_bundle_directory = osdk_output_directory.join(target_name);
|
||||
let bundle = create_base_and_cached_build(
|
||||
@ -73,6 +38,82 @@ pub fn execute_run_command(config: &Config, gdb_server_args: &GdbServerArgs) {
|
||||
bundle.run(&config, ActionChoice::Run);
|
||||
}
|
||||
|
||||
fn adapt_for_gdb_server(config: &mut Config, gdb_server_str: &str) -> Option<VscLaunchConfig> {
|
||||
let gdb_server_args = GdbServerArgs::from_str(gdb_server_str);
|
||||
|
||||
// Add GDB server arguments to QEMU.
|
||||
let qemu_gdb_args = {
|
||||
let gdb_stub_addr = gdb_server_args.host_addr.as_str();
|
||||
match gdb::stub_type_of(gdb_stub_addr) {
|
||||
gdb::StubAddrType::Unix => {
|
||||
format!(
|
||||
" -chardev socket,path={},server=on,wait=off,id=gdb0 -gdb chardev:gdb0",
|
||||
gdb_stub_addr
|
||||
)
|
||||
}
|
||||
gdb::StubAddrType::Tcp => {
|
||||
format!(
|
||||
" -gdb tcp:{}",
|
||||
gdb::tcp_addr_util::format_tcp_addr(gdb_stub_addr)
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
config.run.qemu.args += &qemu_gdb_args;
|
||||
|
||||
if gdb_server_args.wait_client {
|
||||
config.run.qemu.args += " -S";
|
||||
}
|
||||
|
||||
// Ensure debug info added when debugging in the release profile.
|
||||
if config.run.build.profile.contains("release") {
|
||||
config
|
||||
.run
|
||||
.build
|
||||
.override_configs
|
||||
.push(format!("profile.{}.debug=true", config.run.build.profile));
|
||||
}
|
||||
|
||||
gdb_server_args.vsc_launch_file.then(|| {
|
||||
vsc::check_gdb_config(&gdb_server_args);
|
||||
let profile = super::util::profile_name_adapter(&config.run.build.profile);
|
||||
vsc::VscLaunchConfig::new(profile, &gdb_server_args.host_addr)
|
||||
})
|
||||
}
|
||||
|
||||
struct GdbServerArgs {
|
||||
host_addr: String,
|
||||
wait_client: bool,
|
||||
vsc_launch_file: bool,
|
||||
}
|
||||
|
||||
impl GdbServerArgs {
|
||||
fn from_str(args: &str) -> Self {
|
||||
let mut host_addr = ".osdk-gdb-socket".to_string();
|
||||
let mut wait_client = false;
|
||||
let mut vsc_launch_file = false;
|
||||
|
||||
for arg in args.split(",") {
|
||||
let kv = arg.split('=').collect::<Vec<_>>();
|
||||
match kv.as_slice() {
|
||||
["addr", addr] => host_addr = addr.to_string(),
|
||||
["wait-client"] => wait_client = true,
|
||||
["vscode"] => vsc_launch_file = true,
|
||||
_ => {
|
||||
error_msg!("Invalid GDB server argument: {}", arg);
|
||||
exit(Errno::Cli as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GdbServerArgs {
|
||||
host_addr,
|
||||
wait_client,
|
||||
vsc_launch_file,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod gdb {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum StubAddrType {
|
||||
@ -115,7 +156,6 @@ mod gdb {
|
||||
|
||||
mod vsc {
|
||||
use crate::{
|
||||
cli::GdbServerArgs,
|
||||
commands::util::bin_file_name,
|
||||
util::{get_cargo_metadata, get_current_crate_info},
|
||||
};
|
||||
@ -125,7 +165,7 @@ mod vsc {
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use super::gdb;
|
||||
use super::{gdb, GdbServerArgs};
|
||||
|
||||
const VSC_DIR: &str = ".vscode";
|
||||
|
||||
@ -174,6 +214,7 @@ mod vsc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VscLaunchConfig {
|
||||
fn drop(&mut self) {
|
||||
// remove generated files
|
||||
@ -209,14 +250,6 @@ mod vsc {
|
||||
use crate::{error::Errno, error_msg};
|
||||
use std::process::exit;
|
||||
|
||||
if !args.enabled {
|
||||
error_msg!(
|
||||
"No need for a VSCode launch file without launching GDB server,\
|
||||
pass '-h' for help"
|
||||
);
|
||||
exit(Errno::ParseMetadata as _);
|
||||
}
|
||||
|
||||
// check GDB server address
|
||||
let gdb_stub_addr = args.host_addr.as_str();
|
||||
if gdb_stub_addr.is_empty() {
|
||||
@ -224,7 +257,9 @@ mod vsc {
|
||||
exit(Errno::ParseMetadata as _);
|
||||
}
|
||||
if gdb::stub_type_of(gdb_stub_addr) != gdb::StubAddrType::Tcp {
|
||||
error_msg!("Non-TCP GDB server address is not supported under '--gdb-vsc' currently");
|
||||
error_msg!(
|
||||
"Non-TCP GDB server address is not supported under '--gdb-server vscode' currently"
|
||||
);
|
||||
exit(Errno::ParseMetadata as _);
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,15 @@
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Errno {
|
||||
CreateCrate = 1,
|
||||
GetMetadata = 2,
|
||||
AddRustToolchain = 3,
|
||||
ParseMetadata = 4,
|
||||
ExecuteCommand = 5,
|
||||
BuildCrate = 6,
|
||||
RunBundle = 7,
|
||||
BadCrateName = 8,
|
||||
Cli = 1,
|
||||
CreateCrate = 2,
|
||||
GetMetadata = 3,
|
||||
AddRustToolchain = 4,
|
||||
ParseMetadata = 5,
|
||||
ExecuteCommand = 6,
|
||||
BuildCrate = 7,
|
||||
RunBundle = 8,
|
||||
BadCrateName = 9,
|
||||
}
|
||||
|
||||
/// Print error message to console
|
||||
|
@ -82,9 +82,7 @@ mod qemu_gdb_feature {
|
||||
let mut instance = cargo_osdk([
|
||||
"run",
|
||||
"--gdb-server",
|
||||
"--gdb-wait-client",
|
||||
"--gdb-server-addr",
|
||||
unix_socket.as_str(),
|
||||
format!("addr={},wait-client", unix_socket.as_str()).as_str(),
|
||||
]);
|
||||
instance.current_dir(&workspace.os_dir());
|
||||
|
||||
@ -112,8 +110,8 @@ mod qemu_gdb_feature {
|
||||
let mut gdb = Command::new("gdb");
|
||||
gdb.args(["-ex", format!("target remote {}", addr).as_str()]);
|
||||
gdb.write_stdin("\n")
|
||||
.write_stdin("c\n")
|
||||
.write_stdin("quit\n");
|
||||
.write_stdin("quit\n")
|
||||
.write_stdin("y\n");
|
||||
gdb.assert().success();
|
||||
}
|
||||
mod vsc {
|
||||
@ -132,18 +130,15 @@ mod qemu_gdb_feature {
|
||||
let mut instance = cargo_osdk([
|
||||
"run",
|
||||
"--gdb-server",
|
||||
"--gdb-wait-client",
|
||||
"--gdb-vsc",
|
||||
"--gdb-server-addr",
|
||||
addr,
|
||||
format!("wait-client,vscode,addr={}", addr).as_str(),
|
||||
]);
|
||||
instance.current_dir(&workspace.os_dir());
|
||||
|
||||
let dir = workspace.os_dir();
|
||||
let bin_file_path = Path::new(&workspace.os_dir())
|
||||
.join("target")
|
||||
.join("x86_64-unknown-none")
|
||||
.join("debug")
|
||||
.join("osdk")
|
||||
.join(kernel_name)
|
||||
.join(format!("{}-osdk-bin", kernel_name));
|
||||
let _gdb = std::thread::spawn(move || {
|
||||
while !bin_file_path.exists() {
|
||||
|
Reference in New Issue
Block a user