Skip to content

Commit

Permalink
Add more command: continue, step, ... (#62)
Browse files Browse the repository at this point in the history
* Add more command: continue, step, ...

* Add feature cfg for all_stop and lldb
  • Loading branch information
yurydelendik authored Sep 3, 2020
1 parent db28f8d commit 1e14865
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 7 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ num-traits = "0.2.12"
assert_cli = "0.5.4"
env_logger = "0.4.3"
which = "1.0.3"

[features]
all_stop = []
lldb = []
157 changes: 150 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ enum FeatureSupported<'a> {
Value(&'a str),
}

/// Defines target for the set_current_thread command.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SetThreadFor {
/// For 'Continue' command.
Continue,
/// For `ReadRegister` command.
ReadRegister,
}

#[derive(Clone, Debug, PartialEq)]
enum Query<'a> {
/// Return the attached state of the indicated process.
Expand Down Expand Up @@ -162,6 +171,14 @@ enum Query<'a> {
/// How long to read (at most!)
length: u64,
},
/// Register info
#[cfg(feature = "lldb")]
RegisterInfo(u64),
/// Process info
#[cfg(feature = "lldb")]
ProcessInfo,
/// Symbol
Symbol(String, String),
}

/// Part of a process id.
Expand Down Expand Up @@ -337,12 +354,16 @@ enum Command<'a> {
// Write specified region of memory.
WriteMemory(MemoryRegion, Vec<u8>),
Query(Query<'a>),
#[cfg(feature = "all_stop")]
Continue,
#[cfg(feature = "all_stop")]
Step,
Reset,
PingThread(ThreadId),
CtrlC,
UnknownVCommand,
/// Set the current thread for future commands, such as `ReadRegister`.
SetCurrentThread(ThreadId),
SetCurrentThread(SetThreadFor, ThreadId),
/// Insert a software breakpoint.
InsertSoftwareBreakpoint(Breakpoint),
/// Insert a hardware breakpoint
Expand Down Expand Up @@ -432,6 +453,21 @@ named!(q_search_memory<&[u8], (u64, u64, Vec<u8>)>,
data: hex_byte_sequence >>
(address, length, data))));

#[cfg(feature = "lldb")]
fn lldb_query<'a>(i: &'a [u8]) -> IResult<&'a [u8], Query<'a>> {
alt!(i,
tag!("qProcessInfo") => { |_| Query::ProcessInfo }
| preceded!(tag!("qRegisterInfo"), hex_value) => {
|reg| Query::RegisterInfo(reg)
}
)
}

#[cfg(not(feature = "lldb"))]
fn lldb_query<'a>(_i: &'a [u8]) -> IResult<&'a [u8], Query<'a>> {
IResult::Error(error_position!(ErrorKind::Alt, _i))
}

fn query<'a>(i: &'a [u8]) -> IResult<&'a [u8], Query<'a>> {
alt_complete!(i,
tag!("qC") => { |_| Query::CurrentThread }
Expand Down Expand Up @@ -472,6 +508,11 @@ fn query<'a>(i: &'a [u8]) -> IResult<&'a [u8], Query<'a>> {
| preceded!(tag!("qThreadExtraInfo,"), parse_thread_id) => {
|thread_id| Query::ThreadInfo(thread_id)
}
| tuple!(
preceded!(tag!("qSymbol:"), map_res!(take_until!(":"), str::from_utf8)),
preceded!(tag!(":"), map_res!(eof!(), str::from_utf8))) => {
|(sym_value, sym_name): (&str, &str)| Query::Symbol(sym_value.to_owned(), sym_name.to_owned())
}
| tuple!(
preceded!(tag!("qXfer:"), map_res!(take_until!(":"), str::from_utf8)),
preceded!(tag!(":read:"), map_res!(take_until!(":"), str::from_utf8)),
Expand All @@ -484,6 +525,9 @@ fn query<'a>(i: &'a [u8]) -> IResult<&'a [u8], Query<'a>> {
length,
}
}
| lldb_query => {
|q| q
}
)
}

Expand Down Expand Up @@ -714,8 +758,15 @@ fn v_command<'a>(i: &'a [u8]) -> IResult<&'a [u8], Command<'a>> {
}

// Parse the H packet.
named!(parse_h_packet<&[u8], ThreadId>,
preceded!(tag!("Hg"), parse_thread_id));
named!(parse_h_packet<&[u8], (SetThreadFor, ThreadId)>,
alt_complete!(
preceded!(tag!("Hg"), parse_thread_id) => {
|id| (SetThreadFor::ReadRegister, id)
}
| preceded!(tag!("Hc"), parse_thread_id) => {
|id| (SetThreadFor::Continue, id)
}
));

// Parse the D packet.
named!(parse_d_packet<&[u8], Option<u64>>,
Expand Down Expand Up @@ -870,14 +921,27 @@ fn parse_z_packet<'a>(i: &'a [u8]) -> IResult<&'a [u8], Command<'a>> {
}
}

#[cfg(feature = "all_stop")]
fn all_stop_command<'a>(i: &'a [u8]) -> IResult<&'a [u8], Command<'a>> {
alt!(i,
tag!("c") => { |_| Command::Continue }
| tag!("s") => { |_| Command::Step }
)
}

#[cfg(not(feature = "all_stop"))]
fn all_stop_command<'a>(_i: &'a [u8]) -> IResult<&'a [u8], Command<'a>> {
IResult::Error(error_position!(ErrorKind::Alt, _i))
}

fn command<'a>(i: &'a [u8]) -> IResult<&'a [u8], Command<'a>> {
alt!(i,
tag!("!") => { |_| Command::EnableExtendedMode }
| tag!("?") => { |_| Command::TargetHaltReason }
| parse_d_packet => { |pid| Command::Detach(pid) }
| tag!("g") => { |_| Command::ReadGeneralRegisters }
| write_general_registers => { |bytes| Command::WriteGeneralRegisters(bytes) }
| parse_h_packet => { |thread_id| Command::SetCurrentThread(thread_id) }
| parse_h_packet => { |(f, thread_id)| Command::SetCurrentThread(f, thread_id) }
| tag!("k") => { |_| Command::Kill(None) }
| read_memory => { |(addr, length)| Command::ReadMemory(MemoryRegion::new(addr, length)) }
| write_memory => { |(addr, length, bytes)| Command::WriteMemory(MemoryRegion::new(addr, length), bytes) }
Expand All @@ -890,6 +954,7 @@ fn command<'a>(i: &'a [u8]) -> IResult<&'a [u8], Command<'a>> {
| v_command => { |command| command }
| write_memory_binary => { |(addr, length, bytes)| Command::WriteMemory(MemoryRegion::new(addr, length), bytes) }
| parse_z_packet => { |command| command }
| all_stop_command => { |command| command }
)
}

Expand Down Expand Up @@ -954,6 +1019,15 @@ pub enum StopReason {
// NewThread(ThreadId),
}

/// Symbol lookup response.
#[derive(Clone, Debug)]
pub enum SymbolLookupResponse {
/// No symbol name.
Ok,
/// New symbol name.
Symbol(String),
}

/// This trait should be implemented by servers. Methods in the trait
/// generally default to returning `Error::Unimplemented`; but some
/// exceptions are noted below. Methods that must be implemented in
Expand Down Expand Up @@ -1063,7 +1137,7 @@ pub trait Handler {
}

/// Set the current thread for future operations.
fn set_current_thread(&self, _id: ThreadId) -> Result<(), Error> {
fn set_current_thread(&self, _for: SetThreadFor, _id: ThreadId) -> Result<(), Error> {
Err(Error::Unimplemented)
}

Expand Down Expand Up @@ -1210,6 +1284,39 @@ pub trait Handler {
fn fs(&self) -> Result<&dyn FileSystem, ()> {
Err(())
}

/// Continues execution.
#[cfg(feature = "all_stop")]
fn process_continue(&self) -> Result<StopReason, Error> {
Err(Error::Unimplemented)
}

/// Step execution.
#[cfg(feature = "all_stop")]
fn process_step(&self) -> Result<StopReason, Error> {
Err(Error::Unimplemented)
}

/// Notifies about symbol requests.
fn process_symbol(
&self,
_sym_value: &str,
_sym_name: &str,
) -> Result<SymbolLookupResponse, Error> {
Err(Error::Unimplemented)
}

/// Returns information about specified register.
#[cfg(feature = "lldb")]
fn register_info(&self, _reg: u64) -> Result<String, Error> {
Err(Error::Unimplemented)
}

/// Returns process information.
#[cfg(feature = "lldb")]
fn process_info(&self) -> Result<String, Error> {
Err(Error::Unimplemented)
}
}

fn compute_checksum_incremental(bytes: &[u8], init: u8) -> u8 {
Expand Down Expand Up @@ -1241,6 +1348,7 @@ enum Response<'a> {
VContFeatures(Cow<'static, [VContFeature]>),
ThreadList(Vec<ThreadId>),
HostIOResult(HostIOResult),
SymbolName(String),
}

impl<'a, T> From<Result<T, Error>> for Response<'a>
Expand Down Expand Up @@ -1367,6 +1475,15 @@ impl<'a> From<Vec<ThreadId>> for Response<'a> {
}
}

impl<'a> From<SymbolLookupResponse> for Response<'a> {
fn from(response: SymbolLookupResponse) -> Self {
match response {
SymbolLookupResponse::Ok => Response::Ok,
SymbolLookupResponse::Symbol(n) => Response::SymbolName(n),
}
}
}

impl<'a> From<HostIOResult> for Response<'a> {
fn from(result: HostIOResult) -> Self {
Response::HostIOResult(result)
Expand Down Expand Up @@ -1443,6 +1560,16 @@ impl From<HostStat> for Vec<u8> {
}
}

fn write_hex_data<W>(writer: &mut W, data: &[u8]) -> io::Result<()>
where
W: Write,
{
for b in data {
write!(writer, "{:02x}", b)?;
}
Ok(())
}

fn write_binary_data<W>(writer: &mut W, data: &[u8]) -> io::Result<()>
where
W: Write,
Expand Down Expand Up @@ -1567,6 +1694,10 @@ where
}
}
}
Response::SymbolName(name) => {
write!(writer, "qSymbol:")?;
write_hex_data(&mut writer, name.as_bytes())?;
}
Response::HostIOResult(result) => match result {
HostIOResult::Ok => write!(writer, "F0")?,
HostIOResult::Error(errno) => {
Expand Down Expand Up @@ -1649,8 +1780,14 @@ where
handler.write_memory(region.address, &bytes[..]).into()
}
}
Command::SetCurrentThread(thread_id) => handler.set_current_thread(thread_id).into(),
Command::SetCurrentThread(f, thread_id) => {
handler.set_current_thread(f, thread_id).into()
}
Command::Detach(pid) => handler.detach(pid).into(),
#[cfg(feature = "all_stop")]
Command::Continue => handler.process_continue().into(),
#[cfg(feature = "all_stop")]
Command::Step => handler.process_step().into(),

Command::Query(Query::Attached(pid)) => handler.attached(pid).into(),
Command::Query(Query::CurrentThread) => handler.current_thread().into(),
Expand Down Expand Up @@ -1695,7 +1832,13 @@ where
offset,
length,
}) => handler.read_bytes(object, annex, offset, length).into(),

#[cfg(feature = "lldb")]
Command::Query(Query::RegisterInfo(reg)) => handler.register_info(reg).into(),
#[cfg(feature = "lldb")]
Command::Query(Query::ProcessInfo) => handler.process_info().into(),
Command::Query(Query::Symbol(sym_value, sym_name)) => {
handler.process_symbol(&sym_value, &sym_name).into()
}
Command::PingThread(thread_id) => handler.ping_thread(thread_id).into(),
// Empty means "not implemented".
Command::CtrlC => Response::Empty,
Expand Down

0 comments on commit 1e14865

Please sign in to comment.