mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add internal kernel debugger.
This commit is contained in:
parent
cd1cc19b01
commit
df0c842b77
4 changed files with 690 additions and 1 deletions
|
@ -83,6 +83,7 @@ copy.o \
|
|||
$(CPU)/calltrace.o \
|
||||
$(CPU)/kthread.o \
|
||||
crc32.o \
|
||||
debugger.o \
|
||||
descriptor.o \
|
||||
dispmsg.o \
|
||||
dtable.o \
|
||||
|
|
645
sortix/debugger.cpp
Normal file
645
sortix/debugger.cpp
Normal file
|
@ -0,0 +1,645 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
debugger.cpp
|
||||
Internal kernel debugger.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/keycodes.h>
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/cpu.h>
|
||||
#include <sortix/kernel/debugger.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/symbol.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
|
||||
#include "kb/layout/us.h"
|
||||
|
||||
namespace Sortix {
|
||||
namespace Debugger {
|
||||
|
||||
uint16_t* const VIDEO_MEMORY = (uint16_t*) 0xB8000;
|
||||
|
||||
bool first_f10;
|
||||
static int column;
|
||||
static int row;
|
||||
static Thread* current_thread;
|
||||
#define current_process (current_thread->process)
|
||||
|
||||
// Changes the position of the hardware cursor.
|
||||
void SetCursor(int x, int y)
|
||||
{
|
||||
unsigned value = x + y * 80;
|
||||
|
||||
// This sends a command to indicies 14 and 15 in the
|
||||
// CRT Control Register of the VGA controller. These
|
||||
// are the high and low bytes of the index that show
|
||||
// where the hardware cursor is to be 'blinking'.
|
||||
CPU::OutPortB(0x3D4, 14);
|
||||
CPU::OutPortB(0x3D5, (value >> 8) & 0xFF);
|
||||
CPU::OutPortB(0x3D4, 15);
|
||||
CPU::OutPortB(0x3D5, (value >> 0) & 0xFF);
|
||||
}
|
||||
|
||||
void GetCursor(int* x, int* y)
|
||||
{
|
||||
CPU::OutPortB(0x3D4, 14);
|
||||
uint8_t high = CPU::InPortB(0x3D5);
|
||||
CPU::OutPortB(0x3D4, 15);
|
||||
uint8_t low = CPU::InPortB(0x3D5);
|
||||
unsigned value = high << 8 | low;
|
||||
*x = value % 80;
|
||||
*y = value / 80;
|
||||
}
|
||||
|
||||
uint16_t* Character(int x, int y)
|
||||
{
|
||||
return &VIDEO_MEMORY[y * 80 + x];
|
||||
}
|
||||
|
||||
void Scroll()
|
||||
{
|
||||
for ( int y = 0; y < 25-1; y++ )
|
||||
for ( int x = 0; x < 80; x++ )
|
||||
*Character(x, y) = *Character(x, y+1);
|
||||
for ( int x = 0; x < 80; x++ )
|
||||
*Character(x, 25-1) = 0x700 | ' ';
|
||||
}
|
||||
|
||||
void Newline()
|
||||
{
|
||||
if ( row + 1 == 25 )
|
||||
Scroll();
|
||||
else
|
||||
row++;
|
||||
column = 0;
|
||||
}
|
||||
|
||||
void PrintChar(char c)
|
||||
{
|
||||
if ( c == '\n' )
|
||||
Newline();
|
||||
else if ( c == '\b' )
|
||||
{
|
||||
if ( column )
|
||||
column--;
|
||||
else if ( row )
|
||||
column = 80,
|
||||
row--;
|
||||
*Character(column, row) = 0x700 | ' ';
|
||||
}
|
||||
else if ( c == '\r' )
|
||||
column = 0;
|
||||
else if ( c == '\t' )
|
||||
{
|
||||
do PrintChar(' ');
|
||||
while ( column % 8 != 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( column == 80 )
|
||||
Newline();
|
||||
*Character(column++, row) = 0x700 | (uint16_t) c;
|
||||
}
|
||||
|
||||
SetCursor(column, row);
|
||||
}
|
||||
|
||||
void PrintString(const char* str)
|
||||
{
|
||||
while ( *str )
|
||||
PrintChar(*str++);
|
||||
}
|
||||
|
||||
size_t PrintCallback(void* /*user*/, const char* str, size_t len)
|
||||
{
|
||||
for ( size_t i = 0; i < len; i++ )
|
||||
PrintChar(str[i]);
|
||||
return len;
|
||||
}
|
||||
|
||||
void Print(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vprintf_callback(PrintCallback, NULL, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void PrintSymbol(const char* symbol)
|
||||
{
|
||||
if ( !symbol )
|
||||
{
|
||||
Print("<unknown>");
|
||||
return;
|
||||
}
|
||||
if ( !(symbol[0] == '_' && symbol[1] == 'Z') )
|
||||
{
|
||||
Print("%s(...)", symbol);
|
||||
return;
|
||||
}
|
||||
symbol += 2;
|
||||
while ( *symbol )
|
||||
{
|
||||
if ( *symbol == 'N' )
|
||||
symbol++;
|
||||
else if ( '0' <= *symbol && *symbol <= '9' )
|
||||
{
|
||||
size_t len = strtoul(symbol, (char**) &symbol, 10);
|
||||
for ( size_t i = 0; i < len; i++ )
|
||||
PrintChar(*symbol++);
|
||||
if ( *symbol == 'L' )
|
||||
symbol++; // TODO: What is this?
|
||||
if ( '0' <= *symbol && *symbol <= '9' )
|
||||
Print("::");
|
||||
}
|
||||
else if ( *symbol == 'v' )
|
||||
{
|
||||
symbol++;
|
||||
Print("()");
|
||||
break;
|
||||
}
|
||||
else if ( *symbol == 'i' )
|
||||
{
|
||||
symbol++;
|
||||
Print("(...)");
|
||||
break;
|
||||
}
|
||||
else if ( *symbol == 'E' || *symbol == 'P' )
|
||||
{
|
||||
symbol++;
|
||||
if ( *symbol == 'v' )
|
||||
Print("()");
|
||||
else
|
||||
Print("(...)");
|
||||
break;
|
||||
}
|
||||
else
|
||||
PrintChar(*symbol++);
|
||||
}
|
||||
}
|
||||
|
||||
static bool MatchesSymbol(const Symbol* symbol, uintptr_t address)
|
||||
{
|
||||
return symbol->address <= address &&
|
||||
address <= symbol->address + symbol->size;
|
||||
}
|
||||
|
||||
const char* GetSymbolName(uintptr_t address)
|
||||
{
|
||||
if ( const char* symbol_name = GetKernelSymbolName(address) )
|
||||
return symbol_name;
|
||||
for ( size_t i = 0; i < current_process->symbol_table_length; i++ )
|
||||
{
|
||||
const Symbol* symbol = current_process->symbol_table + i;
|
||||
if ( MatchesSymbol(symbol, address) )
|
||||
return symbol->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ReadCommand(char* buffer, size_t buffer_length)
|
||||
{
|
||||
KBLayoutUS kblayout;
|
||||
bool scancode_escaped = false;
|
||||
|
||||
size_t written = 0;
|
||||
while ( true )
|
||||
{
|
||||
// Get a scancode from the keyboard.
|
||||
uint16_t iobase = 0x60;
|
||||
const uint16_t DATA = 0x0;
|
||||
//const uint16_t COMMAND = 0x0;
|
||||
const uint16_t STATUS = 0x4;
|
||||
while ( (CPU::InPortB(iobase + STATUS) & (1<<0)) == 0 );
|
||||
uint8_t scancode = CPU::InPortB(iobase + DATA);
|
||||
|
||||
// Handle escaped scancodes.
|
||||
const uint8_t SCANCODE_ESCAPE = 0xE0;
|
||||
if ( (scancode_escaped = scancode == SCANCODE_ESCAPE) )
|
||||
continue;
|
||||
|
||||
// Produce a <sortix/keycodes.h> format integer.
|
||||
int offset = (scancode_escaped) ? 0x80 : 0;
|
||||
int kbkey = scancode & 0x7F;
|
||||
if ( scancode & 0x80 ) { kbkey = -kbkey - offset; }
|
||||
else { kbkey = kbkey + offset; }
|
||||
|
||||
if ( !written && kbkey == -KBKEY_F10 )
|
||||
{
|
||||
if ( !first_f10 )
|
||||
{
|
||||
strncpy(buffer, "exit", buffer_length);
|
||||
break;
|
||||
}
|
||||
first_f10 = false;
|
||||
}
|
||||
|
||||
// Translate the keystroke into unicode.
|
||||
uint32_t unicode = kblayout.Translate(kbkey);
|
||||
|
||||
if ( !unicode )
|
||||
continue;
|
||||
|
||||
// Ignore depressed keys.
|
||||
if ( kbkey < 0 )
|
||||
continue;
|
||||
|
||||
// Discard anything but ascii.
|
||||
if ( 128 <= unicode )
|
||||
continue;
|
||||
|
||||
char c = (char) unicode;
|
||||
|
||||
// Discard tabs.
|
||||
if ( c == '\t' )
|
||||
continue;
|
||||
|
||||
// Handle backspace.
|
||||
if ( c == '\b' )
|
||||
{
|
||||
if ( !written )
|
||||
continue;
|
||||
PrintChar(c);
|
||||
written--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Truncate the user input if it is too long.
|
||||
if ( written == buffer_length && c != '\n' )
|
||||
continue;
|
||||
|
||||
PrintChar(c);
|
||||
|
||||
// Finish reading the line.
|
||||
if ( c == '\n' )
|
||||
{
|
||||
buffer[written] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[written++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
Process* FindProcess(pid_t least_pid, pid_t max_pid)
|
||||
{
|
||||
Process* best = NULL;
|
||||
if ( least_pid <= current_process->pid && current_process->pid <= max_pid )
|
||||
best = current_process;
|
||||
Thread* first_thread = current_thread;
|
||||
for ( Thread* iter = first_thread->schedulerlistnext;
|
||||
iter != first_thread; iter = iter->schedulerlistnext )
|
||||
if ( least_pid <= iter->process->pid && iter->process->pid <= max_pid &&
|
||||
(!best || iter->process->pid < best->pid) )
|
||||
best = iter->process;
|
||||
return best;
|
||||
}
|
||||
|
||||
int ThreadId(Thread* thread)
|
||||
{
|
||||
int ret = 0;
|
||||
while ( thread->prevsibling )
|
||||
ret++, thread = thread->prevsibling;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main_bt(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
CPU::InterruptRegisters regs;
|
||||
current_thread->LoadRegisters(®s);
|
||||
#if defined(__x86_64__)
|
||||
unsigned long ip = regs.rip;
|
||||
unsigned long bp = regs.rbp;
|
||||
#elif defined(__i386__)
|
||||
unsigned long ip = regs.eip;
|
||||
unsigned long bp = regs.ebp;
|
||||
#endif
|
||||
|
||||
bool userspace = false;
|
||||
unsigned long depth = 0;
|
||||
do
|
||||
{
|
||||
if ( 4*1024*1024 <= ip && !userspace )
|
||||
Print(" -- userspace --\n"), userspace = true;
|
||||
const char* symbol = GetSymbolName(ip);
|
||||
Print("%-4lu 0x%zx ", depth, ip);
|
||||
PrintSymbol(symbol);
|
||||
Print("\n");
|
||||
if ( !bp )
|
||||
break;
|
||||
ip = ((unsigned long*) bp)[1];
|
||||
bp = ((unsigned long*) bp)[0];
|
||||
depth++;
|
||||
} while ( ip );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_dump(int argc, char* argv[])
|
||||
{
|
||||
unsigned long word_size = 0;
|
||||
if ( !strcmp(argv[0], "dump8") ) word_size = 1;
|
||||
if ( !strcmp(argv[0], "dump16") ) word_size = 2;
|
||||
if ( !strcmp(argv[0], "dump32") ) word_size = 4;
|
||||
if ( !strcmp(argv[0], "dump64") ) word_size = 8;
|
||||
if ( argc < 2 )
|
||||
return 0;
|
||||
|
||||
unsigned long start = strtoul(argv[1], NULL, 0);
|
||||
unsigned long length = 1;
|
||||
if ( 3 <= argc )
|
||||
length = strtoul(argv[2], NULL, 0);
|
||||
|
||||
uint8_t* data = (uint8_t*) start;
|
||||
for ( size_t i = 0; i < length; i++ )
|
||||
{
|
||||
size_t elemlen = (word_size ? word_size : 1) ;
|
||||
size_t outlen = elemlen * 2;
|
||||
if ( 80 - column < (int) outlen )
|
||||
Print("\n");
|
||||
if ( !column )
|
||||
#if __WORDSIZE == 64
|
||||
Print("%016lX: ", start + i * elemlen);
|
||||
#else
|
||||
Print("%08lX: ", start + i * elemlen);
|
||||
#endif
|
||||
else if ( word_size )
|
||||
Print(" ");
|
||||
// TODO: Endianness!
|
||||
for ( size_t n = 0; n < (word_size ? word_size : 1); n++ )
|
||||
Print("%02X", data[i * elemlen + n]);
|
||||
}
|
||||
|
||||
if ( column )
|
||||
Print("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_echo(int argc, char* argv[])
|
||||
{
|
||||
const char* prefix = "";
|
||||
for ( int i = 1; i < argc; i++ )
|
||||
Print("%s%s", prefix, argv[i]),
|
||||
prefix = " ";
|
||||
Print("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_exit(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main_pid(int argc, char* argv[])
|
||||
{
|
||||
if ( 2 <= argc )
|
||||
{
|
||||
int pid = atoi(argv[1]);
|
||||
Process* process = FindProcess(pid, pid);
|
||||
if ( !process )
|
||||
{
|
||||
Print("pid: %i: No such process\n", pid);
|
||||
return 1;
|
||||
}
|
||||
current_thread = process->firstthread;
|
||||
Memory::SwitchAddressSpace(current_thread->addrspace);
|
||||
}
|
||||
Print("%c %i\t`%s'\n", '*', (int) current_process->pid,
|
||||
current_process->program_image_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_ps(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
pid_t least = 0;
|
||||
while ( Process* process = FindProcess(least, INT_MAX) )
|
||||
{
|
||||
Print("%c %i\t`%s'\n", process == current_process ? '*' : ' ',
|
||||
(int) process->pid, process->program_image_path);
|
||||
least = process->pid + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_rs(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
CPU::InterruptRegisters regs;
|
||||
current_thread->LoadRegisters(®s);
|
||||
#if defined(__x86_64__)
|
||||
Print("rax=0x%lx, ", regs.rax);
|
||||
Print("rbx=0x%lx, ", regs.rbx);
|
||||
Print("rcx=0x%lx, ", regs.rcx);
|
||||
Print("rdx=0x%lx, ", regs.rdx);
|
||||
Print("rdi=0x%lx, ", regs.rdi);
|
||||
Print("rsi=0x%lx, ", regs.rsi);
|
||||
Print("rsp=0x%lx, ", regs.userrsp);
|
||||
Print("rbp=0x%lx, ", regs.rbp);
|
||||
Print("r8=0x%lx, ", regs.r8);
|
||||
Print("r9=0x%lx, ", regs.r9);
|
||||
Print("r10=0x%lx, ", regs.r10);
|
||||
Print("r11=0x%lx, ", regs.r11);
|
||||
Print("r12=0x%lx, ", regs.r12);
|
||||
Print("r13=0x%lx, ", regs.r13);
|
||||
Print("r14=0x%lx, ", regs.r14);
|
||||
Print("r15=0x%lx, ", regs.r15);
|
||||
Print("rip=0x%lx, ", regs.rip);
|
||||
Print("rflags=0x%lx, ", regs.rflags);
|
||||
Print("int_no=%lu, ", regs.int_no);
|
||||
Print("err_code=0x%lx, ", regs.err_code);
|
||||
Print("cs=0x%lx, ", regs.cs);
|
||||
Print("ds=0x%lx, ", regs.ds);
|
||||
Print("ss=0x%lx, ", regs.ss);
|
||||
Print("kerrno=%lu, ", regs.kerrno);
|
||||
Print("cr2=%lx, ", regs.cr2);
|
||||
Print("signal_pending=%lu.", regs.signal_pending);
|
||||
#elif defined(__i386__)
|
||||
Print("eax=0x%lx, ", regs.eax);
|
||||
Print("ebx=0x%lx, ", regs.ebx);
|
||||
Print("ecx=0x%lx, ", regs.ecx);
|
||||
Print("edx=0x%lx, ", regs.edx);
|
||||
Print("edi=0x%lx, ", regs.edi);
|
||||
Print("esi=0x%lx, ", regs.esi);
|
||||
Print("esp=0x%lx, ", regs.useresp);
|
||||
Print("ebp=0x%lx, ", regs.ebp);
|
||||
Print("eip=0x%lx, ", regs.eip);
|
||||
Print("eflags=0x%lx, ", regs.eflags);
|
||||
Print("int_no=%lu, ", regs.int_no);
|
||||
Print("err_code=0x%lx, ", regs.err_code);
|
||||
Print("cs=0x%lx, ", regs.cs);
|
||||
Print("ds=0x%lx, ", regs.ds);
|
||||
Print("ss=0x%lx, ", regs.ss);
|
||||
Print("kerrno=%lu, ", regs.kerrno);
|
||||
Print("cr2=%lx, ", regs.cr2);
|
||||
Print("signal_pending=%lu.", regs.signal_pending);
|
||||
#endif
|
||||
Print("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DescribeThread(int tid, Thread* thread)
|
||||
{
|
||||
CPU::InterruptRegisters regs;
|
||||
thread->LoadRegisters(®s);
|
||||
#if defined(__x86_64__)
|
||||
unsigned long ip = regs.rip;
|
||||
#elif defined(__i386__)
|
||||
unsigned long ip = regs.eip;
|
||||
#endif
|
||||
|
||||
Print("%c ", thread == current_thread ? '*' : ' ');
|
||||
Print("%i", tid);
|
||||
Print("\tip=0x%lx", ip);
|
||||
Print("\n");
|
||||
}
|
||||
|
||||
int main_tid(int argc, char* argv[])
|
||||
{
|
||||
if ( 2 <= argc )
|
||||
{
|
||||
int tid = atoi(argv[1]);
|
||||
Thread* thread = current_process->firstthread;
|
||||
for ( int i = 0; i < tid && thread; i++ )
|
||||
thread = thread->nextsibling;
|
||||
if ( !thread )
|
||||
{
|
||||
Print("tid: %i: No such thread\n", tid);
|
||||
return 1;
|
||||
}
|
||||
current_thread = thread;
|
||||
Memory::SwitchAddressSpace(current_thread->addrspace);
|
||||
}
|
||||
DescribeThread(ThreadId(current_thread), current_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main_ts(int /*argc*/, char* /*argv*/[])
|
||||
{
|
||||
int tid = 0;
|
||||
for ( Thread* thread = current_process->firstthread; thread; thread = thread->nextsibling )
|
||||
DescribeThread(tid++, thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct command_registration
|
||||
{
|
||||
const char* command;
|
||||
int (*function)(int, char*[]);
|
||||
const char* help;
|
||||
};
|
||||
|
||||
|
||||
static const struct command_registration commands[] =
|
||||
{
|
||||
"bt", main_bt, "bt Stack trace",
|
||||
"dump", main_dump, "dump START [LEN] Dump continuous memory",
|
||||
"dump8", main_dump, "dump8 START [LEN] Dump 8-bit memory words",
|
||||
"dump16", main_dump, "dump16 START [LEN] Dump 16-bit memory words",
|
||||
"dump32", main_dump, "dump32 START [LEN] Dump 32-bit memory words",
|
||||
"dump64", main_dump, "dump16 START [LEN] Dump 64-bit memory words",
|
||||
"echo", main_echo, "echo [ARG...] Echo string",
|
||||
"exit", main_exit, "exit Quit debugger",
|
||||
"pid", main_pid, "pid [NEWPID] Change current process",
|
||||
"ps", main_ps, "ps List processes",
|
||||
"rs", main_rs, "rs Print registers",
|
||||
"tid", main_tid, "tid [NEWTID] Change current thread",
|
||||
"ts", main_ts, "ts List threads in current process",
|
||||
NULL, NULL, NULL,
|
||||
};
|
||||
|
||||
bool RunCommand()
|
||||
{
|
||||
const size_t BUFFER_LENGTH = 256;
|
||||
static char buffer[BUFFER_LENGTH];
|
||||
Print("> ");
|
||||
ReadCommand(buffer, BUFFER_LENGTH-1);
|
||||
|
||||
static char* argv[256];
|
||||
|
||||
int argc = 0;
|
||||
char* input = buffer;
|
||||
char* saved = NULL;
|
||||
while ( (argv[argc] = strtok_r(input, " \t\n", &saved)) )
|
||||
argc++, input = NULL;
|
||||
|
||||
if ( !argc )
|
||||
return true;
|
||||
|
||||
if ( !strcmp(argv[0], "help") )
|
||||
{
|
||||
Print("You can use the following kernel debugger commands:\n");
|
||||
for ( size_t i = 0; commands[i].command; i++ )
|
||||
Print("%s\n", commands[i].help);
|
||||
Print("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( size_t i = 0; commands[i].command; i++ )
|
||||
if ( !strcmp(argv[0], commands[i].command) )
|
||||
return commands[i].function(argc, argv) != -1;
|
||||
|
||||
Print("%s: No such kernel debugger command\n", argv[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
static uint16_t saved_video_memory[80*25];
|
||||
|
||||
current_thread = CurrentThread();
|
||||
|
||||
bool was_enabled = Interrupt::SetEnabled(false);
|
||||
|
||||
first_f10 = true;
|
||||
|
||||
addr_t saved_addrspace = current_thread->addrspace;
|
||||
|
||||
memcpy(saved_video_memory, VIDEO_MEMORY, sizeof(saved_video_memory));
|
||||
int saved_x, saved_y;
|
||||
GetCursor(&saved_x, &saved_y);
|
||||
|
||||
column = saved_x, row = saved_y;
|
||||
Print("\nSortix kernel debugger - type `help' for help.\n");
|
||||
|
||||
while ( RunCommand() );
|
||||
SetCursor(saved_x, saved_y);
|
||||
memcpy(VIDEO_MEMORY, saved_video_memory, sizeof(saved_video_memory));
|
||||
|
||||
Memory::SwitchAddressSpace(saved_addrspace);
|
||||
|
||||
Interrupt::SetEnabled(was_enabled);
|
||||
}
|
||||
|
||||
} // namespace Debugger
|
||||
} // namespace Sortix
|
36
sortix/include/sortix/kernel/debugger.h
Normal file
36
sortix/include/sortix/kernel/debugger.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/debugger.h
|
||||
Internal kernel debugger.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_DEBUGGER_H
|
||||
#define INCLUDE_SORTIX_KERNEL_DEBUGGER_H
|
||||
|
||||
namespace Sortix {
|
||||
namespace Debugger {
|
||||
|
||||
void Run();
|
||||
|
||||
} // namespace Debugger
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -23,8 +23,10 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/debugger.h>
|
||||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
#include <sortix/kernel/cpu.h>
|
||||
|
||||
#include <sortix/keycodes.h>
|
||||
|
@ -88,9 +90,14 @@ namespace Sortix
|
|||
work->kb->InterruptWork(work->scancode);
|
||||
}
|
||||
|
||||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* /*regs*/)
|
||||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
uint8_t scancode = PopScancode();
|
||||
if ( scancode == KBKEY_F10 )
|
||||
{
|
||||
CurrentThread()->SaveRegisters(regs);
|
||||
Debugger::Run();
|
||||
}
|
||||
PS2KeyboardWork work;
|
||||
work.kb = this;
|
||||
work.scancode = scancode;
|
||||
|
|
Loading…
Reference in a new issue