mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-30 10:38:55 +00:00
6a57683e52
The new monitor component at os/src/monitor is the designated successor of the gdb_monitor. This initial version, however, implements only the subset needed to inspect the memory of the monitored component(s). In contrast to the gdb_monitor, the new component supports the monitoring of multiple components, leveraging the sandbox API. It can therefore be used as a drop-in replacement for the init component. Like the gdb_monitor, the new monitor speaks the GDB protocol over Genode's terminal session. But the protocol implementation does not re-use any gdbserver code, sidestepping the complexities of POSIX. There exist two run scripts illustrating the new component. The os/run/monitor.run script exercises memory inspection via the 'm' command by letting a test program monitor itself. The os/run/monitor_gdb.run script allows for the interactive use of GDB to interact with monitored components. Issue #4917
118 lines
2.6 KiB
C++
118 lines
2.6 KiB
C++
/*
|
|
* \brief GDB packet parser
|
|
* \author Norman Feske
|
|
* \date 2023-05-11
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2023 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _MONITOR__GDB_PACKET_H_
|
|
#define _MONITOR__GDB_PACKET_H_
|
|
|
|
#include <util/string.h>
|
|
|
|
namespace Genode { template <size_t> struct Gdb_packet; }
|
|
|
|
|
|
template <Genode::size_t MAX_SIZE>
|
|
struct Genode::Gdb_packet
|
|
{
|
|
enum class State {
|
|
IDLE, INCOMPLETE,
|
|
EXPECT_CHECKSUM1, EXPECT_CHECKSUM2,
|
|
COMPLETE, CORRUPT
|
|
};
|
|
|
|
State state { State::IDLE };
|
|
|
|
unsigned cursor = 0;
|
|
|
|
struct Checksum
|
|
{
|
|
uint8_t accumulated;
|
|
uint8_t expected;
|
|
|
|
bool matches() const { return (accumulated == expected); }
|
|
};
|
|
|
|
Checksum checksum { };
|
|
|
|
char buf[MAX_SIZE] { };
|
|
|
|
void reset()
|
|
{
|
|
state = State::IDLE;
|
|
cursor = 0;
|
|
checksum = { };
|
|
}
|
|
|
|
enum class Append_result { OK, COMPLETE, OVERFLOW, CORRUPT };
|
|
|
|
Append_result append(char const c)
|
|
{
|
|
if (cursor >= sizeof(buf))
|
|
return Append_result::OVERFLOW;
|
|
|
|
auto interpret = [&]
|
|
{
|
|
auto is_hex_digit = [] (char c) { return is_digit(c, true); };
|
|
auto hex_digit = [] (char c) { return digit (c, true); };
|
|
|
|
if (state == State::EXPECT_CHECKSUM1 || state == State::EXPECT_CHECKSUM2)
|
|
if (!is_hex_digit(c))
|
|
return State::CORRUPT;
|
|
|
|
switch (state) {
|
|
|
|
case State::IDLE:
|
|
return (c == '$') ? State::INCOMPLETE
|
|
: State::IDLE;
|
|
case State::INCOMPLETE:
|
|
return (c == '#') ? State::EXPECT_CHECKSUM1
|
|
: State::INCOMPLETE;
|
|
case State::EXPECT_CHECKSUM1:
|
|
checksum.expected = uint8_t(hex_digit(c) << 4u);
|
|
return State::EXPECT_CHECKSUM2;
|
|
|
|
case State::EXPECT_CHECKSUM2:
|
|
checksum.expected |= uint8_t(hex_digit(c));
|
|
return checksum.matches() ? State::COMPLETE
|
|
: State::CORRUPT;
|
|
case State::COMPLETE:
|
|
case State::CORRUPT:
|
|
break; /* expect call of 'reset' */
|
|
};
|
|
return state;
|
|
};
|
|
|
|
State const orig_state = state;
|
|
|
|
state = interpret();
|
|
|
|
/* capture only the command payload between '$' and '#' */
|
|
if ((orig_state == State::INCOMPLETE) && (state == State::INCOMPLETE)) {
|
|
buf[cursor++] = c;
|
|
checksum.accumulated = uint8_t(checksum.accumulated + c);
|
|
}
|
|
|
|
return (state == State::COMPLETE) ? Append_result::COMPLETE :
|
|
(state == State::CORRUPT) ? Append_result::CORRUPT :
|
|
Append_result::OK;
|
|
}
|
|
|
|
bool complete() const { return state == State::COMPLETE; }
|
|
|
|
void with_command(auto const &fn) const
|
|
{
|
|
if (complete())
|
|
fn(Const_byte_range_ptr { buf, cursor });
|
|
}
|
|
};
|
|
|
|
#endif /* _MONITOR__GDB_PACKET_H_ */
|