Skip to content

Commit

Permalink
feat(debugger): add trigger command (close #39)
Browse files Browse the repository at this point in the history
  • Loading branch information
godzie44 committed Jan 31, 2025
1 parent ce2daef commit 87a4a5c
Show file tree
Hide file tree
Showing 12 changed files with 436 additions and 50 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ Of course, the debugger provides many more commands:
alias: `reg write`)
- `register info` - print list of registers with it values (alias: `reg info`)
- `sharedlib info` - show list of shared libraries
- `trigger` - define a list of commands that will be executed when a certain event is triggered (at a breakpoint or watchpoint hit), see `help trigger` for more info
- `quit` - exit the BugStalker (alias: `q`)

## Tui interface
Expand Down
2 changes: 1 addition & 1 deletion src/debugger/breakpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ impl UninitBreakpoint {
brkpt.number,
brkpt.place,
BrkptType::UserDefined,
Some(brkpt.debug_info_file).map(|path| path.into()),
Some(brkpt.debug_info_file),
)
}

Expand Down
2 changes: 2 additions & 0 deletions src/ui/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod step_out;
pub mod step_over;
pub mod symbol;
pub mod thread;
pub mod trigger;
pub mod variables;
pub mod watch;

Expand Down Expand Up @@ -64,6 +65,7 @@ pub enum Command {
SkipInput,
Oracle(String, Option<String>),
Async(r#async::Command),
Trigger(trigger::Command),
Help {
command: Option<String>,
reason: Option<String>,
Expand Down
95 changes: 94 additions & 1 deletion src/ui/command/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub mod expression;

use super::r#break::BreakpointIdentity;
use super::{frame, memory, r#async, register, source_code, thread, watch, Command, CommandError};
use super::{
frame, memory, r#async, register, source_code, thread, trigger, watch, Command, CommandError,
};
use super::{r#break, CommandResult};
use crate::debugger::register::debug::BreakCondition;
use crate::debugger::variable::dqe::Dqe;
Expand Down Expand Up @@ -76,6 +78,11 @@ pub const ASYNC_COMMAND_STEP_OVER_SUBCOMMAND: &str = "stepover";
pub const ASYNC_COMMAND_STEP_OVER_SUBCOMMAND_SHORT: &str = "next";
pub const ASYNC_COMMAND_STEP_OUT_SUBCOMMAND: &str = "stepout";
pub const ASYNC_COMMAND_STEP_OUT_SUBCOMMAND_SHORT: &str = "finish";
pub const TRIGGER_COMMAND: &str = "trigger";
pub const TRIGGER_COMMAND_ANY_TRIGGER_SUBCOMMAND: &str = "any";
pub const TRIGGER_COMMAND_BRKPT_TRIGGER_SUBCOMMAND: &str = "b";
pub const TRIGGER_COMMAND_WP_TRIGGER_SUBCOMMAND: &str = "w";
pub const TRIGGER_COMMAND_INFO_SUBCOMMAND: &str = "info";
pub const HELP_COMMAND: &str = "help";
pub const HELP_COMMAND_SHORT: &str = "h";

Expand Down Expand Up @@ -468,6 +475,40 @@ impl Command {
)))
.boxed();

let trigger = op(TRIGGER_COMMAND)
.ignore_then(choice((
choice((
sub_op(TRIGGER_COMMAND_INFO_SUBCOMMAND).to(trigger::Command::Info),
sub_op(TRIGGER_COMMAND_ANY_TRIGGER_SUBCOMMAND).to(
trigger::Command::AttachToDefined(trigger::TriggerEvent::Any),
),
sub_op(TRIGGER_COMMAND_BRKPT_TRIGGER_SUBCOMMAND)
.ignore_then(text::int(10))
.from_str()
.unwrapped()
.map(|num| {
trigger::Command::AttachToDefined(trigger::TriggerEvent::Breakpoint(
num,
))
}),
sub_op(TRIGGER_COMMAND_WP_TRIGGER_SUBCOMMAND)
.ignore_then(text::int(10))
.from_str()
.unwrapped()
.map(|num| {
trigger::Command::AttachToDefined(trigger::TriggerEvent::Watchpoint(
num,
))
}),
))
.padded(),
end()
.to(trigger::Command::AttachToPreviouslyCreated)
.padded(),
)))
.map(Command::Trigger)
.boxed();

let oracle = op_w_arg(ORACLE_COMMAND)
.ignore_then(text::ident().padded().then(text::ident().or_not()))
.map(|(name, subcmd)| {
Expand Down Expand Up @@ -498,6 +539,7 @@ impl Command {
command(ORACLE_COMMAND, oracle),
command(WATCH_COMMAND, watchpoint),
command(ASYNC_COMMAND, r#async),
command(TRIGGER_COMMAND, trigger),
))
}

Expand Down Expand Up @@ -1078,6 +1120,57 @@ fn test_parser() {
));
},
},
TestCase {
inputs: vec!["trigger", " trigger "],
command_matcher: |result| {
assert!(matches!(
result.unwrap(),
Command::Trigger(trigger::Command::AttachToPreviouslyCreated)
));
},
},
TestCase {
inputs: vec!["trigger any", " trigger any "],
command_matcher: |result| {
assert!(matches!(
result.unwrap(),
Command::Trigger(trigger::Command::AttachToDefined(
trigger::TriggerEvent::Any
))
));
},
},
TestCase {
inputs: vec!["trigger info", " trigger info "],
command_matcher: |result| {
assert!(matches!(
result.unwrap(),
Command::Trigger(trigger::Command::Info)
));
},
},
TestCase {
inputs: vec!["trigger b 1", " trigger b 1 "],
command_matcher: |result| {
assert!(matches!(
result.unwrap(),
Command::Trigger(trigger::Command::AttachToDefined(
trigger::TriggerEvent::Breakpoint(num)
)) if num == 1
));
},
},
TestCase {
inputs: vec!["trigger w 2", " trigger w 2 "],
command_matcher: |result| {
assert!(matches!(
result.unwrap(),
Command::Trigger(trigger::Command::AttachToDefined(
trigger::TriggerEvent::Watchpoint(num)
)) if num == 2
));
},
},
TestCase {
inputs: vec!["oracle tokio", " oracle tokio "],
command_matcher: |result| {
Expand Down
25 changes: 25 additions & 0 deletions src/ui/command/trigger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::fmt::{Display, Formatter};

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum TriggerEvent {
Breakpoint(u32),
Watchpoint(u32),
Any,
}

impl Display for TriggerEvent {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
TriggerEvent::Breakpoint(num) => write!(f, "Breakpoint {num}"),
TriggerEvent::Watchpoint(num) => write!(f, "Watchpoint {num}"),
TriggerEvent::Any => write!(f, "Any breakpoint or watchpoint"),
}
}
}

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum Command {
AttachToPreviouslyCreated,
AttachToDefined(TriggerEvent),
Info,
}
18 changes: 15 additions & 3 deletions src/ui/console/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ use crate::ui::command::parser::{
SOURCE_COMMAND_FUNCTION_SUBCOMMAND, STEP_INSTRUCTION_COMMAND, STEP_INTO_COMMAND,
STEP_INTO_COMMAND_SHORT, STEP_OUT_COMMAND, STEP_OUT_COMMAND_SHORT, STEP_OVER_COMMAND,
STEP_OVER_COMMAND_SHORT, SYMBOL_COMMAND, THREAD_COMMAND, THREAD_COMMAND_CURRENT_SUBCOMMAND,
THREAD_COMMAND_INFO_SUBCOMMAND, THREAD_COMMAND_SWITCH_SUBCOMMAND, VAR_COMMAND, VAR_LOCAL_KEY,
WATCH_COMMAND, WATCH_COMMAND_SHORT, WATCH_INFO_SUBCOMMAND, WATCH_REMOVE_SUBCOMMAND,
WATCH_REMOVE_SUBCOMMAND_SHORT,
THREAD_COMMAND_INFO_SUBCOMMAND, THREAD_COMMAND_SWITCH_SUBCOMMAND, TRIGGER_COMMAND,
TRIGGER_COMMAND_ANY_TRIGGER_SUBCOMMAND, TRIGGER_COMMAND_BRKPT_TRIGGER_SUBCOMMAND,
TRIGGER_COMMAND_INFO_SUBCOMMAND, TRIGGER_COMMAND_WP_TRIGGER_SUBCOMMAND, VAR_COMMAND,
VAR_LOCAL_KEY, WATCH_COMMAND, WATCH_COMMAND_SHORT, WATCH_INFO_SUBCOMMAND,
WATCH_REMOVE_SUBCOMMAND, WATCH_REMOVE_SUBCOMMAND_SHORT,
};
use chumsky::prelude::{any, choice, just};
use chumsky::text::whitespace;
Expand Down Expand Up @@ -417,6 +419,16 @@ pub fn create_editor(
SOURCE_COMMAND_FUNCTION_SUBCOMMAND.to_string(),
],
},
CommandHint {
short: None,
long: TRIGGER_COMMAND.to_string(),
subcommands: vec![
TRIGGER_COMMAND_INFO_SUBCOMMAND.to_string(),
TRIGGER_COMMAND_ANY_TRIGGER_SUBCOMMAND.to_string(),
TRIGGER_COMMAND_BRKPT_TRIGGER_SUBCOMMAND.to_string(),
TRIGGER_COMMAND_WP_TRIGGER_SUBCOMMAND.to_string(),
],
},
CommandHint {
short: None,
long: ASYNC_COMMAND.to_string(),
Expand Down
42 changes: 28 additions & 14 deletions src/ui/console/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ thread info|current|switch <number> -- show list of threads or current (
sharedlib info -- show list of shared libraries
source asm|fn|<bounds> -- show source code or assembly instructions for current (in focus) function
async backtrace|backtrace all|task -- commands for async rust
trigger info|any|<>|b <number>|w <number> -- define a list of commands that will be executed when a certain event is triggered
oracle <oracle> <>|<subcommand> -- execute a specific oracle
h, help <>|<command> -- show help
tui -- change ui mode to tui
Expand Down Expand Up @@ -94,7 +95,7 @@ pub const HELP_VAR: &str = "\
\x1b[32;1mvar\x1b[0m
Show local and global variables, supports data queries expressions over variables (see `help dqe`).
Available subcomands:
Available subcommands:
var locals - print current stack frame local variables
var <name or expression> - print local and global variables with selected name
Expand All @@ -112,7 +113,7 @@ pub const HELP_ARG: &str = "\
\x1b[32;1marg\x1b[0m
Show current stack frame arguments, supports data queries expressions over arguments (see `help dqe`).
Available subcomands:
Available subcommands:
arg all - print all arguments
arg <name or expression> - print argument with selected name
Expand All @@ -126,7 +127,7 @@ pub const HELP_BACKTRACE: &str = "\
\x1b[32;1mbt, backtrace\x1b[0m
Show backtrace of all stack frames in current thread or from all threads.
Available subcomands:
Available subcommands:
backtrace all - show backtrace for all running threads
backtrace - show backtrace of current thread
Expand All @@ -141,7 +142,7 @@ pub const HELP_FRAME: &str = "\
\x1b[32;1mf, frame\x1b[0m
Show current stack frame info or set frame to focus.
Available subcomands:
Available subcommands:
frame info - show current stack frame information (see output explanation)
frame switch <number> - set frame <number> to focus
Expand Down Expand Up @@ -184,12 +185,12 @@ pub const HELP_BREAK: &str = "\
\x1b[32;1mb, break\x1b[0m
Manage breakpoints.
Available subcomands:
Available subcommands:
break <location> - set breakpoint to location
break remove <location>|<number> - deactivate and delete selected breakpoint
break info - show all breakpoints
Posible location format:
Possible location format:
- at instruction. Example: break 0x55555555BD30
- at function start. A function can be defined by its full name (with namespace)
or by function name (in case of possible collisions, breakpoints will be set in
Expand All @@ -207,7 +208,7 @@ or raw memory region have a different lifetimes. Watchpoints for global variable
are lives until BugStalker session is alive. On the contrary, watchpoints for local variables
are lives until debugee is not restarted, and will be removed automatically.
Available subcomands:
Available subcommands:
watch +rw|+w| <addr:size> - set write or read-write watchpoint (write by default) to memory location [addr; addr+size], size must be one of [1,2,4,8] bytes
watch +rw|+w| <expression> - set write or read-write watchpoint (write by default) to DQE result (see `help dqe`), expression result must one of [1,2,4,8] bytes
watch remove <addr:size>|<expression>|<number> - deactivate and delete selected watchpoint
Expand All @@ -225,15 +226,15 @@ pub const HELP_SYMBOL: &str = "\
\x1b[32;1msymbol\x1b[0m
Print symbols matched by regular expression.
Available subcomands:
Available subcommands:
symbol <name_regex>
";

pub const HELP_MEMORY: &str = "\
\x1b[32;1mmem, memory\x1b[0m
Read or write into debugged program memory.
Available subcomands:
Available subcommands:
memory read <address> - print 8-byte block at address in debugee memory
memory write <address> <value> - writes 8-byte value to address in debugee memory
";
Expand All @@ -242,7 +243,7 @@ pub const HELP_REGISTER: &str = "\
\x1b[32;1mreg, register\x1b[0m
Read, write, or view debugged program registers (x86_64 registers support).
Available subcomands:
Available subcommands:
register read <reg_name> - print value of register by name (x86_64 register name in lowercase)
register write <reg_name> <value> - set new value to register by name
register info - print list of registers with it values
Expand All @@ -252,7 +253,7 @@ pub const HELP_THREAD: &str = "\
\x1b[32;1mthread\x1b[0m
Show threads information or set thread to focus.
Available subcomands:
Available subcommands:
thread info - print list of thread information
thread current - prints thread that has focus
thread switch <number> - set thread <number> to focus
Expand All @@ -262,15 +263,15 @@ pub const HELP_SHARED_LIB: &str = "\
\x1b[32;1msharedlib\x1b[0m
Show shared libraries information.
Available subcomands:
Available subcommands:
sharedlib info - print list of loaded shared libraries and their mapping addresses
";

pub const HELP_SOURCE: &str = "\
\x1b[32;1msource\x1b[0m
Show source code or assembly instructions for current (in focus) function.
Available subcomands:
Available subcommands:
source fn - show code of function in focus
source asm - show assembly of function in focus
source <bounds> - show line in focus with <bounds> lines up and down of this line
Expand All @@ -280,7 +281,7 @@ pub const HELP_ASYNC: &str = "\
\x1b[32;1masync\x1b[0m
Commands for async rust (currently for tokio runtime only).
Available subcomands:
Available subcommands:
async backtrace - show state of async workers and blocking threads
async backtrace all - show state of async workers and blocking threads, show info about all running tasks
async task <async_fn_regex> - show active task (active task means a task that is running on the thread that is currently in focus) if `async_fn_regex` parameter is empty,
Expand All @@ -289,6 +290,18 @@ async next, async stepover - perform a stepover within the context of the curren
async finish, async stepout - execute the program until the current task moves into the completed state
";

pub const HELP_TRIGGER: &str = "\
\x1b[32;1mtrigger\x1b[0m
Define a list of commands that will be executed when a certain event is triggered (at a breakpoint or watchpoint hit).
Available subcommands:
trigger any - define a list of commands that will be executed when any breakpoint or watchpoint is hit
trigger - define a list of commands that will be executed when a previously defined breakpoint or watchpoint is hit
trigger b <number> - define a list of commands that will be executed when the given breakpoint is hit
trigger w <number> - define a list of commands that will be executed when the given watchpoint is hit
trigger info - show the list of triggers
";

pub const HELP_TUI: &str = "\
\x1b[32;1mtui\x1b[0m
Change ui mode to terminal ui.
Expand Down Expand Up @@ -342,6 +355,7 @@ impl Helper {
Some(parser::SHARED_LIB_COMMAND) => HELP_SHARED_LIB,
Some(parser::SOURCE_COMMAND) => HELP_SOURCE,
Some(parser::ASYNC_COMMAND) => HELP_ASYNC,
Some(parser::TRIGGER_COMMAND) => HELP_TRIGGER,
Some(parser::ORACLE_COMMAND) => self.oracle_help.get_or_insert_with(|| {
let mut help = HELP_ORACLE.to_string();
let oracles = debugger.all_oracles();
Expand Down
Loading

0 comments on commit 87a4a5c

Please sign in to comment.