Max OS 0.3
Loading...
Searching...
No Matches
MaxOS::runtime::GDBServer Class Reference

Handler for running a GDB server over serial. More...

#include <gdbstub.h>

Inheritance diagram for MaxOS::runtime::GDBServer:
MaxOS::hardwarecommunication::InterruptHandler

Public Member Functions

 GDBServer (console::SerialConsole *serial)
 Constructs a handler for remote debugging using GDB, also sets up interrupt handlers for traps and breakpoints.
 
void attach (processes::Thread *thread)
 Begin debugging a thread, will start paused.
 
string get_checksum (const string &payload)
 Calculates the GDB checksum of a command.
 
bool check_checksum (const string &payload, const string &checksum)
 Validates the checksum of a commnad.
 
string build_message (const string &payload)
 Converts a message into the form GDB expects, including and ACK package.
 
void send_message (const string &payload)
 Converts a message to the required form and sends it over serial.
 
void send_empty ()
 Send an empty message to the GDB server.
 
void send_supported (const string &peer_supported)
 Sends the features that this GDB stub supports to the GDB server.
 
void send_registers ()
 Sends the registers of the thread to the GDB server.
 
void send_memory (const string &message)
 Send a chunk of memory to the GDB server.
 
void send_memory (void *address, size_t length)
 Send a chunk of memory to the GDB server.
 
void send_breakpoint_reached ()
 
void handle_step_instruction ()
 Set the trap flag and allow the thread to run.
 
void handle_set_breakpoint (const string &message)
 Set a software break point by replacing the instruction with a INT3.
 
void handle_set_breakpoint (void *address)
 Set a software break point by replacing the instruction with a INT3.
 
void handle_remove_breakpoint (const string &message)
 Remove a software break point, and replace the original opcode.
 
void handle_remove_breakpoint (void *address)
 Remove a software break point, and replace the original opcode.
 
void handle_continue ()
 Continues the exeuction of the thread, acknowledges the request and allows the thread to run.
 
void handle_detach ()
 Detaches the thread from the GDB, removing all breakpoints and allowing it to be scheduled as usual.
 
processes::Thread * attached_thread ()
 Get the attached thread.
 
- Public Member Functions inherited from MaxOS::hardwarecommunication::InterruptHandler
virtual system::cpu_status_t * handle_interrupt (system::cpu_status_t *status)
 Handles an interrupt and returns the status.
 

Public Attributes

system::cpu_status_t thread_regs
 

Additional Inherited Members

- Protected Member Functions inherited from MaxOS::hardwarecommunication::InterruptHandler
 InterruptHandler (uint8_t interrupt_number, int64_t redirect=-1, uint64_t redirect_index=0)
 Creates a new interrupt handler and registers it with the interrupt manager.
 
virtual ~InterruptHandler ()
 Destroys the interrupt handler and unregisters it from the interrupt manager.
 
- Protected Attributes inherited from MaxOS::hardwarecommunication::InterruptHandler
uint8_t m_interrupt_number
 The interrupt number this handler handles.
 

Detailed Description

Handler for running a GDB server over serial.

Definition at line 71 of file gdbstub.h.

Constructor & Destructor Documentation

◆ GDBServer()

GDBServer::GDBServer ( console::SerialConsole *  serial)

Constructs a handler for remote debugging using GDB, also sets up interrupt handlers for traps and breakpoints.

Parameters
serialThe serial port where GDB will listen/send packets on
Todo:
GDB owns the interrupt here, should move to a serial API

Definition at line 28 of file gdbstub.cpp.

29: InterruptHandler(0x24, 4, 0x18),
30 m_serial(serial),
31 m_trap_flag_handler(this),
32 m_break_point_handler(this)
33{
34}
Handles a certain interrupt number.
Definition interrupts.h:44

Member Function Documentation

◆ attach()

void GDBServer::attach ( processes::Thread *  thread)

Begin debugging a thread, will start paused.

Parameters
threadThe thread to debug

Definition at line 43 of file gdbstub.cpp.

43 {
44
45 // Pause the thread
46 thread->thread_state = ThreadState::WAITING;
47
48 // Read the thread info
49 m_attached_thread = thread;
50 thread_regs = (const cpu_status_t&)m_attached_thread->execution_state;
51
52}
volatile system::cpu_status_t execution_state
The CPU state of the thread.
Definition process.h:71
struct PACKED MaxOS::system::CPUStatus cpu_status_t
Alias for CPUStatus struct.

References MaxOS::processes::Thread::execution_state, and MaxOS::processes::Thread::thread_state.

◆ attached_thread()

Thread * GDBServer::attached_thread ( )

Get the attached thread.

Returns
The attached thread

Definition at line 536 of file gdbstub.cpp.

536 {
537
538 return m_attached_thread;
539
540}

Referenced by MaxOS::runtime::TrapFlagExcpetion::handle_interrupt(), and MaxOS::runtime::BreakPointException::handle_interrupt().

◆ build_message()

string GDBServer::build_message ( const string &  payload)

Converts a message into the form GDB expects, including and ACK package.

Parameters
payloadThe message to convert
Returns
The message plus its checksum and the related indicators

Definition at line 258 of file gdbstub.cpp.

258 {
259 return "+$"s + payload + "#" + get_checksum(payload);
260}
string get_checksum(const string &payload)
Calculates the GDB checksum of a command.
Definition gdbstub.cpp:222

References get_checksum().

Referenced by send_message().

◆ check_checksum()

bool GDBServer::check_checksum ( const string &  payload,
const string &  checksum 
)

Validates the checksum of a commnad.

Parameters
payloadThe command to validate
checksumThe expected checksum
Returns
True if valid, false otherwise

Definition at line 248 of file gdbstub.cpp.

248 {
249 return get_checksum(payload).to_lower() == checksum;
250}

References get_checksum().

◆ get_checksum()

string GDBServer::get_checksum ( const string &  payload)

Calculates the GDB checksum of a command.

Parameters
payloadThe command to get the checksum of
Returns
The checksum string, always 2 chars wide

Definition at line 222 of file gdbstub.cpp.

222 {
223
224 // Sum each character
225 uint8_t checksum = 0;
226 for (int i = 0; i < payload.length(); ++i)
227 checksum += (uint8_t)payload[i];
228
229 // Take first 8 bits
230 checksum &= 0xFF;
231
232 // Convert to hex
233 string hex = string((uint64_t)checksum);
234 if (hex.length() == 1)
235 hex = "0"s + hex;
236
237 return hex;
238
239}

Referenced by build_message(), and check_checksum().

◆ handle_continue()

void GDBServer::handle_continue ( )

Continues the exeuction of the thread, acknowledges the request and allows the thread to run.

Definition at line 508 of file gdbstub.cpp.

508 {
509
510 // Acknowledge
511 m_serial->write_char('+');
512
513 // Let the thread be scheduled
514 m_attached_thread->thread_state = ThreadState::READY;
515}
void write_char(char c) final
Waits for the serial port to be ready, then writes a character to it.
Definition serial.cpp:99
volatile thread_state_t thread_state
The current state of the thread.
Definition process.h:72

References MaxOS::processes::Thread::thread_state, and MaxOS::console::SerialConsole::write_char().

◆ handle_detach()

void GDBServer::handle_detach ( )

Detaches the thread from the GDB, removing all breakpoints and allowing it to be scheduled as usual.

Definition at line 520 of file gdbstub.cpp.

520 {
521
522 // Remove all breakpoints
523 for (const auto& bp : m_breakpoints)
524 handle_remove_breakpoint(bp.first);
525
526 // Allow program to continue rest of execution
527 m_attached_thread->thread_state = ThreadState::READY;
528
529}
void handle_remove_breakpoint(const string &message)
Remove a software break point, and replace the original opcode.
Definition gdbstub.cpp:457

References handle_remove_breakpoint(), and MaxOS::processes::Thread::thread_state.

◆ handle_remove_breakpoint() [1/2]

void GDBServer::handle_remove_breakpoint ( const string &  message)

Remove a software break point, and replace the original opcode.

Parameters
messageThe GDB command requesting the breakpoint removal

Definition at line 457 of file gdbstub.cpp.

457 {
458
459 // Parse
460 Vector<String> parts = message.substring(2,message.length( ) - 2).split(",");
461 string address_str = parts[1].to_upper();
462
463 handle_remove_breakpoint((void*)address_str.hex_to_uint64());
464
465}

References handle_remove_breakpoint().

Referenced by handle_detach(), and handle_remove_breakpoint().

◆ handle_remove_breakpoint() [2/2]

void GDBServer::handle_remove_breakpoint ( void *  address)

Remove a software break point, and replace the original opcode.

Parameters
addressThe address to break on

Definition at line 472 of file gdbstub.cpp.

472 {
473
474 // Invaild address
475 if (address < (void*)0x1000) {
476 send_message("OK");
477 return;
478 }
479
480 // Doesnt exist
481 auto breakpoint = m_breakpoints.find(address);
482 if (breakpoint == m_breakpoints.end()) {
483 send_message("OK");
484 return;
485 }
486
487 // Switch into the processes' address space
489 MemoryManager::switch_active_memory_manager(GlobalScheduler::get_process(m_attached_thread->parent_pid)->memory_manager);
490
491 // Replace with old byte
492 CPU::disable_write_protect();
493 *(uint8_t*)address = breakpoint->second;
494 CPU::enable_write_protect();
495
496 // Remove reference
497 m_breakpoints.erase(breakpoint);
498
499 // Restore executing process's address space
500 MemoryManager::switch_active_memory_manager(old);
501 send_message("OK");
502
503}
Handles memory allocation and deallocation.
static Process * get_process(uint64_t pid)
Gets a process on the currently executing core by its PID.
static Process * current_process()
Gets the process on the currently executing core.
memory::MemoryManager * memory_manager
The manager for memory used by this process.
Definition process.h:121
uint64_t parent_pid
The parent process ID.
Definition process.h:69
void send_message(const string &payload)
Converts a message to the required form and sends it over serial.
Definition gdbstub.cpp:267

References MaxOS::processes::GlobalScheduler::current_process(), MaxOS::processes::GlobalScheduler::get_process(), MaxOS::processes::Process::memory_manager, MaxOS::processes::Thread::parent_pid, and send_message().

◆ handle_set_breakpoint() [1/2]

void GDBServer::handle_set_breakpoint ( const string &  message)

Set a software break point by replacing the instruction with a INT3.

Parameters
messageThe GDB command requesting the breakpoint

Definition at line 405 of file gdbstub.cpp.

405 {
406
407 // Parse
408 Vector<String> parts = message.substring(2,message.length( ) - 2).split(",");
409 string address_str = parts[1].to_upper();
410
411 handle_set_breakpoint((void*)address_str.hex_to_uint64());
412
413}
void handle_set_breakpoint(const string &message)
Set a software break point by replacing the instruction with a INT3.
Definition gdbstub.cpp:405

References handle_set_breakpoint().

Referenced by handle_set_breakpoint().

◆ handle_set_breakpoint() [2/2]

void GDBServer::handle_set_breakpoint ( void *  address)

Set a software break point by replacing the instruction with a INT3.

Parameters
addressThe address to break on

Definition at line 420 of file gdbstub.cpp.

420 {
421
422 // Invaild address
423 if (address < (void*)0x1000) {
424 send_message("OK");
425 return;
426 }
427
428 // Already set or invalid address
429 if (m_breakpoints.find(address) != m_breakpoints.end()) {
430 send_message("OK");
431 return;
432 }
433
434 // Switch into the processes' address space
436 MemoryManager::switch_active_memory_manager(GlobalScheduler::get_process(m_attached_thread->parent_pid)->memory_manager);
437
438 // Store old byte
439 uint8_t old_byte = *(uint8_t*)address;
440 m_breakpoints.insert(address, old_byte);
441
442 // Replace with breakpoint (INT3)
443 CPU::disable_write_protect();
444 *(uint8_t*)address = 0xCC;
445 CPU::enable_write_protect();
446
447 // Restore executing process's address space
448 MemoryManager::switch_active_memory_manager(old);
449 send_message("OK");
450}

References MaxOS::processes::GlobalScheduler::current_process(), MaxOS::processes::GlobalScheduler::get_process(), MaxOS::processes::Process::memory_manager, MaxOS::processes::Thread::parent_pid, and send_message().

◆ handle_step_instruction()

void GDBServer::handle_step_instruction ( )

Set the trap flag and allow the thread to run.

Definition at line 383 of file gdbstub.cpp.

383 {
384
385 // Acknowledge
386 m_serial->write_char('+');
387
388 // Enable trap flag for the thread and allow it to run
389 thread_regs.rflags |= (1 << 8);
390 m_attached_thread->thread_state = ThreadState::READY;
391
392 // Make sure change is mirrored if not in kernel
393 if (thread_regs.rip == m_attached_thread->execution_state.rip)
394 m_attached_thread->execution_state.rflags |= (1 << 8);
395
396 // wait for the step to occur and be caught by the exception handler
397 // ...
398}

References MaxOS::processes::Thread::execution_state, MaxOS::processes::Thread::thread_state, and MaxOS::console::SerialConsole::write_char().

◆ send_empty()

void GDBServer::send_empty ( )

Send an empty message to the GDB server.

Definition at line 275 of file gdbstub.cpp.

275 {
276 send_message("");
277}

References send_message().

◆ send_memory() [1/2]

void GDBServer::send_memory ( const string &  message)

Send a chunk of memory to the GDB server.

Parameters
messageThe GDB command requesting the chunk

Definition at line 343 of file gdbstub.cpp.

343 {
344
345 // Parse
346 Vector<String> parts = message.substring(1,message.length( ) - 1).split(",");
347 string address_str = parts[0].to_upper();
348 string length_str = parts[1].to_upper();
349
350 send_memory((void*)address_str.hex_to_uint64(), length_str.hex_to_uint64());
351}
void send_memory(const string &message)
Send a chunk of memory to the GDB server.
Definition gdbstub.cpp:343

References send_memory().

Referenced by send_memory().

◆ send_memory() [2/2]

void GDBServer::send_memory ( void *  address,
size_t  length 
)

Send a chunk of memory to the GDB server.

Parameters
addressThe start address of the chunk
lengthHow large the chunk is (in bytes)

Definition at line 359 of file gdbstub.cpp.

359 {
360
361 // Cant read
362 if (address < (void*)0x1000) {
363 send_message("E01");
364 return;
365 }
366
367 // Switch into the processes' address space
369 MemoryManager::switch_active_memory_manager(GlobalScheduler::get_process(m_attached_thread->parent_pid)->memory_manager);
370
371 // Send data
372 String payload(address, length);
373 send_message(payload.to_lower());
374
375 // Restore executing process's address space
376 MemoryManager::switch_active_memory_manager(old);
377
378}

References MaxOS::processes::GlobalScheduler::current_process(), MaxOS::processes::GlobalScheduler::get_process(), MaxOS::processes::Process::memory_manager, MaxOS::processes::Thread::parent_pid, and send_message().

◆ send_message()

void GDBServer::send_message ( const string &  payload)

Converts a message to the required form and sends it over serial.

Parameters
payloadThe message to send

Definition at line 267 of file gdbstub.cpp.

267 {
268 string message = build_message(payload.c_str());
269 m_serial->write(message);
270}
string build_message(const string &payload)
Converts a message into the form GDB expects, including and ACK package.
Definition gdbstub.cpp:258

References build_message().

Referenced by MaxOS::runtime::TrapFlagExcpetion::handle_interrupt(), MaxOS::runtime::BreakPointException::handle_interrupt(), handle_remove_breakpoint(), handle_set_breakpoint(), send_empty(), send_memory(), send_registers(), and send_supported().

◆ send_registers()

void GDBServer::send_registers ( )

Sends the registers of the thread to the GDB server.

Definition at line 300 of file gdbstub.cpp.

300 {
301
302 string payload = "";
303
304 // General Purpose Registers
305 payload += format_register(thread_regs.rax, 8);
306 payload += format_register(thread_regs.rbx, 8);
307 payload += format_register(thread_regs.rcx, 8);
308 payload += format_register(thread_regs.rdx, 8);
309 payload += format_register(thread_regs.rsi, 8);
310 payload += format_register(thread_regs.rdi, 8);
311 payload += format_register(thread_regs.rbp, 8);
312 payload += format_register(thread_regs.rsp, 8);
313
314 // Secondary General Purpose Registers
315 payload += format_register(thread_regs.r8, 8);
316 payload += format_register(thread_regs.r9, 8);
317 payload += format_register(thread_regs.r10, 8);
318 payload += format_register(thread_regs.r11, 8);
319 payload += format_register(thread_regs.r12, 8);
320 payload += format_register(thread_regs.r13, 8);
321 payload += format_register(thread_regs.r14, 8);
322 payload += format_register(thread_regs.r15, 8);
323
324 // Instruction Pointer
325 payload += format_register(thread_regs.rip, 8);
326
327 // Flags / Segments
328 payload += format_register(thread_regs.rflags, 4);
329 payload += format_register(thread_regs.cs, 4);
330 payload += format_register(thread_regs.ss, 4);
331
332 // Remaining
333 payload += "x"s * (8 * 4);
334
335 send_message(payload);
336}

References send_message().

◆ send_supported()

void GDBServer::send_supported ( const string &  peer_supported)

Sends the features that this GDB stub supports to the GDB server.

Parameters
peer_supportedThe features that the server has indicated that it supports

Definition at line 284 of file gdbstub.cpp.

284 {
285
286 string out = "PacketSize=4000;qXfer:features:read+;";
287
288 // Must support hardware breakpoints
289 Vector<string> features = peer_supported.split("+;");
290 for (const auto& feature : features)
291 if (feature == "hwbreak")
292 out += "hwbreak+;";
293
294 send_message(out);
295}

References send_message().

Member Data Documentation

◆ thread_regs

system::cpu_status_t MaxOS::runtime::GDBServer::thread_regs

Definition at line 119 of file gdbstub.h.


The documentation for this class was generated from the following files: