ZealOS/src/Kernel/KDebug.CC

654 lines
15 KiB
HolyC
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Bool CheckPtr(U8 *ptr)
{//Check if addr is valid ptr.
if (mem_heap_base<=ptr<=mem_mapped_space) {
if (*MemPageTable(ptr)&1)
return TRUE;
else
return FALSE;
} else if (ptr<mem_boot_base)
return FALSE;
else if (ptr<VGAM_GRAPHICS)
return TRUE;
else
return FALSE;
}
Bool CheckCodePtr(U8 *ptr)
{//Check if addr is valid code addr.
if (mem_heap_base<=ptr<=mem_heap_limit) {
if (*MemPageTable(ptr)&1)
return TRUE;
else
return FALSE;
} else if (ptr<mem_boot_base)
return FALSE;
else if (ptr<VGAM_GRAPHICS)
return TRUE;
else
return FALSE;
}
Bool CheckOnStack(U8 *ptr,CTask *task=NULL)
{//Check if addr is valid stack addr.
Bool res=FALSE;
PUSHFD
CLI
if (task) {
if (&task->stack->stack_base<=ptr<=
(&task->stack->stack_base)(U8 *)+task->stack->stack_size)
res=TRUE;
} else if (mem_heap_base<=ptr<=mem_heap_limit)
res=TRUE;
POPFD
return res;
}
I64 UnusedStack(CTask *task=NULL)
{//Count of usused bytes in task's stack.
I64 res;
if (!task) task=Fs;
PUSHFD
CLI
if (task==Fs)
res=GetRSP()(U8 *)-(&task->stack->stack_base)(U8 *);
else
res=task->rsp(U8 *)-(&task->stack->stack_base)(U8 *);
POPFD
return res;
}
U8 *Caller(I64 num=1)
{//Returns the addr of the fun which called this one,
//or the caller of the caller, etc.
U8 **rbp=GetRBP,**ptr;
while (num--) {
if (rbp>=*rbp)
return NULL;
rbp=*rbp;
if (!CheckOnStack(rbp,Fs))
return NULL;
}
ptr=rbp+1;
return *ptr;
}
U8 *TaskCaller(CTask *task=NULL,I64 num=0,Bool saved_context=FALSE)
{//Fetches addr of Nth caller on task's stack.
U8 **ptr,**rbp,**rsp;
if (!task) task=Fs;
if (!saved_context && task==Fs)
return Caller(num+1);
if (!TaskValidate(task))
return NULL;
rbp=task->rbp;
rsp=task->rsp;
if (num) {
while (CheckOnStack(rbp,task)) {
ptr=rbp+1;
if (! --num)
return *ptr;
if (rbp>=*rbp)
break;
rbp=*rbp;
}
return NULL;
} else {
if (task->rip==_RET)
return *rsp;
else
return task->rip;
}
}
#define STACK_REP_LEN 32
U0 StackRep(CTask *task=NULL)
{//Reports whats on the stack.
I64 i,j,addr,
**rbp,**rsp,*my_rsp[STACK_REP_LEN];
CHashTable *old_hash=Fs->hash_table;
if (!task) task=Fs;
if (!TaskValidate(task))
return;
PUSHFD
CLI
if (task==Fs) {
rbp=GetRBP;
rsp=rbp+3;
rbp=*rbp;
} else {
rsp=task->rsp;
rbp=task->rbp;
}
if (task->rip==_RET)
addr=*rsp;
else
addr=task->rip;
MemCopy(my_rsp,rsp,STACK_REP_LEN*sizeof(U8 *));
POPFD
Fs->hash_table=task->hash_table;
for (i=0;i<STACK_REP_LEN;i++) {
"%08X [RSP+%04X]: %016X ",rsp+i,
i*sizeof(U8 *),my_rsp[i];
while (TRUE) {
if (!(&task->stack->stack_base<=rbp<
(&task->stack->stack_base)(U8 *)+task->stack->stack_size))
break;
j=rbp-rsp;
if (j>=i)
break;
addr=my_rsp[j+1];
if (rbp>=my_rsp[j])
break;
rbp=my_rsp[j];
}
if (my_rsp[i]==addr)
"$$RED$$";
"%P$$FG$$\n",my_rsp[i];
}
'\n';
Fs->hash_table=old_hash;
}
U0 CallerRep(U8 **rbp=NULL,CTask *task=NULL)
{//Prints a report of calling routines.
I64 **ptr;
if (!task) task=Fs;
if (!rbp) {
if (task==Fs)
rbp=GetRBP;
else
rbp=task->rbp;
}
"CallerRep:\n";
while (CheckOnStack(rbp,task)) {
ptr=rbp+1;
"%08X:%08tX:%P\n",ptr,*ptr,*ptr;
if (rbp>=*rbp)
break;
rbp=*rbp;
}
}
U0 D(U8 *addr,I64 count=0x80,Bool show_offset=TRUE)
{//Dump mem, showing offsets.
//See $LK,"DocD",A="MN:DocD"$() for a live dump.
I64 i,j,ch;
U8 *ptr=addr;
while (count) {
if (show_offset)
"%08X",ptr-addr;
else
"%010X",ptr;
if (count>16)
j=16;
else
j=count;
for (i=0;i<j;i++)
"%02X ",ptr[i];
for (;i<16;i++)
"";
for (i=0;i<j;i++) {
ch=ptr[i];
if (ch<CH_SHIFT_SPACE || ch==CH_BACKSPACE)
ch='.';
'' ch;
if (ch=='$$')
'' ch;
}
'\n';
count-=j;
ptr+=j;
}
}
U0 Dm(U8 *addr,I64 count=0x80)
{//Show mem addr, not offsets.
D(addr,count,FALSE);
}
U0 Da(U8 **addr,I64 count=0x10)
{//Dump mem, showing symbolic addresses.
while (count-->0) {
"%08X:%08X,%P\n",addr,*addr,*addr;
addr++;
}
}
U0 RawPrint(I64 mS=100,U8 *format,...)
{//Print using $LK,"Raw",A="MN:Raw"$ screen output for a length of time.
//$BK,1$Your heap must be good.$BK,0$
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
Bool old_raw,old_input_filter;
PUSHFD
CLI
old_raw=Raw(ON);
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
"%s",buf;
Busy(mS<<10);
POPFD
LBEqual(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
Raw(old_raw);
Free(buf);
}
U0 RawD(I64 mS=100,U8 *addr,I64 count=0x80)
{//Dumps a block of mem using $LK,"Raw",A="MN:Raw"$
//screen output for a fixed length
//of time.
Bool old_raw,old_input_filter;
PUSHFD
CLI
old_raw=Raw(ON);
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
D(addr,count);
Busy(mS<<10);
POPFD
LBEqual(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
Raw(old_raw);
}
U0 RawDm(I64 mS=100,U8 *addr,I64 count=0x80)
{//Dumps a block of mem using $LK,"Raw",A="MN:Raw"$
//screen output for a fixed length
//of time.
Bool old_raw,old_input_filter;
PUSHFD
CLI
old_raw=Raw(ON);
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
Dm(addr,count);
Busy(mS<<10);
POPFD
LBEqual(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
Raw(old_raw);
}
I64 *TaskRegAddr(CTask *task,I64 reg_num)
{
switch (reg_num) {
case REG_RAX: return &task->rax;
case REG_RCX: return &task->rcx;
case REG_RDX: return &task->rdx;
case REG_RBX: return &task->rbx;
case REG_RSP: return &task->rsp;
case REG_RBP: return &task->rbp;
case REG_RSI: return &task->rsi;
case REG_RDI: return &task->rdi;
case 8 : return &task->r8;
case 9 : return &task->r9;
case 10: return &task->r10;
case 11: return &task->r11;
case 12: return &task->r12;
case 13: return &task->r13;
case 14: return &task->r14;
case 15: return &task->r15;
}
return NULL;
}
#define RAWDR_COL 40
U0 RawDr(CTask *task=NULL)
{
I64 i,j,old_col=text.raw_col;
Bool old_raw=Raw(ON);
U8 buf[200];
if (!task) task=Fs;
for (i=0;i<16;i++) {
text.raw_col=i*text.cols+RAWDR_COL;
"<EFBFBD>%3Z:%016X\n",i,"ST_U64_REGS",*TaskRegAddr(task,i);
}
text.raw_col=i++*text.cols+RAWDR_COL;
"<EFBFBD>RIP:%016X\n",task->rip;
text.raw_col=i++*text.cols+RAWDR_COL;
"<EFBFBD>%-*tp\n",text.cols-(RAWDR_COL+1)-1,Fs->rip;
text.raw_col=i++*text.cols+RAWDR_COL;
'<EFBFBD>';
if (Bt(&sys_run_level,RLf_COMPILER)) {
j=Fs->rip;
Ui(buf,&j,,,TRUE);
"%s",buf;
} else
'\n';
text.raw_col=i*text.cols+RAWDR_COL;
'<EFBFBD>';
for (j=0;j<text.cols-RAWDR_COL-1;j++)
'<EFBFBD>';
text.raw_col=old_col;
Raw(old_raw);
}
U0 Dr(CTask *task=NULL)
{//Dump regs
I64 i;
if (!task) task=Fs;
for (i=0;i<16;i++)
"%3Z:%016X\n",i,"ST_U64_REGS",*TaskRegAddr(task,i);
"RIP:%016X\n",task->rip;
}
U8 *SysGetStr2(I64)
{
U8 buf[512];
GetS(buf,512,FALSE);
return StrNew(buf);
}
CBpt *BptFind(U8 *needle_addr,CTask *haystack_task=NULL,Bool rem=FALSE)
{
CBpt *res=NULL,*tmpb,*tmpb1,*tmpb2;
if (!haystack_task) haystack_task=Fs;
PUSHFD
CLI
tmpb1=&haystack_task->bpt_list;
tmpb=haystack_task->bpt_list;
while (tmpb) {
tmpb2=tmpb->next;
if (tmpb->addr==needle_addr) {
res=tmpb;
if (rem)
tmpb1->next=tmpb2;
else
tmpb1=&tmpb->next;
} else
tmpb1=&tmpb->next;
tmpb=tmpb2;
}
POPFD
return res;
}
Bool BptS(U8 *addr,CTask *task=NULL,Bool live=TRUE)
{//Set breakpoint.
CBpt *tmpb;
Bool res=TRUE;
if (!task) task=Fs;
PUSHFD
CLI
if (!(tmpb=BptFind(addr,task,FALSE))) {
tmpb=CAlloc(sizeof(CBpt),task);
tmpb->addr=addr;
tmpb->val=*addr;
res=FALSE;
tmpb->next=task->bpt_list;
task->bpt_list=tmpb;
if (task==Fs && live)
*addr=OC_BPT;
}
POPFD
return res;
}
Bool BptR(U8 *addr,CTask *task=NULL,Bool live=TRUE,Bool rem=TRUE)
{//Remove breakpoint.
CBpt *tmpb;
Bool res=FALSE;
if (!task) task=Fs;
PUSHFD
CLI
if (tmpb=BptFind(addr,task,rem)) {
if (task==Fs && live)
*tmpb->addr=tmpb->val;
res=TRUE;
if (rem)
Free(tmpb);
}
POPFD
return res;
}
Bool B(U8 *addr,CTask *task=NULL,Bool live=TRUE)
{//Toggle breakpoint.
//Return: TRUE if removed.
Bool res=FALSE;
PUSHFD
CLI
if (BptFind(addr,task,FALSE)) {
BptR(addr,task,live,TRUE);
res=TRUE;
} else
BptS(addr,task,live);
POPFD
return res;
}
I64 B2(CTask *task=NULL,Bool live=TRUE)
{//Remove all breakpoints.
//Return: count of removed.
I64 res=0;
CBpt *tmpb,*tmpb1;
if (!task) task=Fs;
PUSHFD
CLI
tmpb=task->bpt_list;
task->bpt_list=NULL;
while (tmpb) {
tmpb1=tmpb->next;
if (task==Fs && live)
*tmpb->addr=tmpb->val;
Free(tmpb);
tmpb=tmpb1;
res++;
}
POPFD
return res;
}
U0 G(U8 *ip=INVALID_PTR,CTask *task=NULL)
{//Go
if (!task) task=Fs;
if (ip!=INVALID_PTR) task->rip=ip;
if (BptFind(task->rip,task))
"\nDo one of the following, first:\n"
">S;\t\t\t//Single step\n"
">B2;\t\t\t//Clear all break points\n"
">G2;\t\t\t//Clear all break points and Go\n\n"
"After resuming, <CTRL-ALT-n> next focus task\n"
"After resuming, <CTRL-ALT-v> flushes screen VGA cache\n";
else {
LBtr(&task->task_flags,TASKf_DISABLE_BPTS);
LBtr(&task->rflags,RFLAGf_TRAP);//No single step
Suspend(task,FALSE);
if (task==Fs) {
if (IsDebugMode && task->next_cc!=&task->next_cc) {
"Exit Debug\n";
Btr(&task->last_cc->flags,CCf_PROMPT);
}
} else
Exit;
}
}
U0 G2(U8 *ip=INVALID_PTR,CTask *task=NULL)
{//Remove all breakpoints and Go.
if (!task) task=Fs;
B2(task);
if (ext[EXT_WIN_FOCUS])
CallExtNum(EXT_WIN_FOCUS,debug.focus_task);
VGAFlush;
G(ip,task);
}
public U0 S(U8 *ip=INVALID_PTR,CTask *task=NULL) //Single-step.
{//Single step.
if (!task) task=Fs;
PUSHFD
CLI
if (ip!=INVALID_PTR) task->rip=ip;
LBts(&task->task_flags,TASKf_DISABLE_BPTS);
LBts(&task->rflags,RFLAGf_TRAP);
Suspend(task,FALSE);
if (task==Fs) {
if (IsDebugMode) {
if (task->next_cc!=&task->next_cc)
Btr(&task->last_cc->flags,CCf_PROMPT);
}
} else
Exit;
POPFD
}
U0 DebugHelp()
{
"\n"
"The cmd line is basically the same as normal. Here are some common\n"
"debugging commands.\n\n"
">EdLite(\"FileName\");\t\t//Edit file.\n"
">D(0x100000);\t\t\t//Dump page tables.\n"
">Dm(0x100000);\t\t\t//Dump page tables.\n"
">Dm(Fs,sizeof(CTask));\t\t//Dump current task record.\n"
">ClassRep(Fs,\"CTask\",1);\t//Dump current task record.\n"
">ClassRep(Fs,,1);\t\t//(It knows lastclass.)\n"
">CallerRep;\t\t\t//Stack trace report.\n"
">Da(_RSP);\t\t\t//Dump stack.\n"
">Dr;\t\t\t\t//Dump Regs.\n"
">1+2*3+&Print;\t\t\t//Show calculation res.\n"
">*(0x70000)(I64 *)=0x123456789;\t//Assign value to 0x70000-0x70007.\n"
">_RAX=0x1234;\t\t\t//Set RAX to 0x1234.\n"
">_RIP=&Break;\t\t//Set RIP.\n"
">I64 i;\t\t\t\t//Declare variable.\n"
">i=_RCX+_RDX;\t\t\t//Assign to variable.\n"
">U(&Print+0x8);\t\t\t//Unassemble Print.\n"
">Uf(\"Print\");\t\t\t//Unassembler function \"Print\".\n"
">Man(\"Print\");\t\t\t//Edit Src for \"Print\".\n"
">E(_RIP);\t\t\t//Edit Src Code.\n"
">Fix;\t\t\t\t//Edit Last Err Src Code.\n"
">B(&Main+0x20);\t\t\t//Toggle break point.\n"
">B2;\t\t\t\t//Clear all break points.\n"
">S;\t\t\t\t//Single step.\n"
">G;\t\t\t\t//Resume execution.\n"
">G2;\t\t\t\t//B2;VGAFlush;WinFocus;G;\n"
">Exit;\t\t\t\t//Exit (kill) task.\n\n"
"After resuming, <CTRL-ALT-n> next focus task.\n"
"After resuming, <CTRL-ALT-v> flushes screen VGA cache.\n\n";
}
U0 Debug2()
{
Bool old_win_inhibit,old_waiting_message,old_single;
I64 i,old_getstr2;
U8 buf[200];
if (debug.panic) {
if (IsRaw) {
i=Fs->rip;
Ui(buf,&i);
"%s",buf;
} else
U(Fs->rip,1);
} else
debug.panic=TRUE;
old_waiting_message=LBtr(&Fs->task_flags,TASKf_AWAITING_MESSAGE);
old_win_inhibit=Fs->win_inhibit;
Fs->win_inhibit=WIG_USER_TASK_DEFAULT;
sys_focus_task=Fs;
kbd.scan_code=0;
old_getstr2=fp_getstr2;
fp_getstr2=&SysGetStr2;
old_single=SingleUser(OFF);
while (!mouse_hard.install_attempts)
Yield;
SingleUser(old_single);
UserTaskCont;
fp_getstr2=old_getstr2;
Fs->win_inhibit=old_win_inhibit;
LBEqual(&Fs->task_flags,TASKf_AWAITING_MESSAGE,old_waiting_message);
}
U0 Fault3(I64 fault_num,I64 fault_err_code)
{
no_warn fault_err_code;
PUSHFD
CLI
if (Gs->num && debug.mp_crash) {
mp_count=1;
debug.mp_crash->cpu_num=Gs->num;
debug.mp_crash->task=Fs;
debug.mp_crash->rip=Fs->rip;
debug.mp_crash->message=debug.message;
debug.mp_crash->message_num=debug.message_num;
MPInt(I_MP_CRASH,0);
SysHlt;
}
"\n\tZenithOS Debugger\n\n"
">Help;\t//For help.\n\n";
Beep(62,TRUE);
if (fault_num==I_DEBUG) {
if (debug.message) {
"\n!!!%s",debug.message;
if (debug.message_num)
"%016X",debug.message_num;
"!!!\n\n";
}
}
if (debug.panic)
CallerRep;
Debug2;
POPFD
}
U0 Fault2(I64 fault_num,I64 fault_err_code)
{//Called from $LK,"Fault2",A="FF:::/Kernel/KInterrupts.CC,Fault2"$.
//$BK,1$Be careful not to swap-out and ruin the saved context$BK,0$
Bool was_raw,was_single_user,was_silent,was_in_debug,was_mouse_enabled;
I64 i,old_raw_flags=text.raw_flags;
was_single_user=SingleUser(ON);
if (!IsDebugMode)
debug.focus_task=sys_focus_task;
sys_focus_task=NULL;
if (fault_num==I_BPT)
Fs->rip--;
if (Fs->debug_task)
CallExtNum(EXT_DEBUG_RESUME,fault_num,fault_err_code);
else {
was_mouse_enabled = CallExtStr("MouseEnable", FALSE);
was_raw=Raw(ON);
was_silent=Silent(OFF);
text.raw_flags|=RWF_SHOW_DOLLAR|RWF_SCROLL;
"Task \"";
"%s",Fs->task_title;
"\"\n";
"Fault:0x%02X %Z\t\tErr Code:%08X\n",
fault_num,fault_num,"ST_INT_NAMES",fault_err_code;
was_in_debug=DebugMode(ON);
"RIP:%08X",Fs->rip; //Sometimes crashes on %p, so do this first
":%pRSP:%08X\n",Fs->rip,Fs->rsp;
if (fault_num==I_PAGE_FAULT) {
MOV_RAX_CR2
i=GetRAX;
"Fault Addr:%08X:%p\n",i,i;
}
Fault3(fault_num,fault_err_code);
DebugMode(was_in_debug);
Silent(was_silent);
Raw(was_raw);
CallExtStr("MouseEnable", was_mouse_enabled);
text.raw_flags=old_raw_flags;
}
SingleUser(was_single_user);
if (LBtr(&Fs->task_flags,TASKf_KILL_AFTER_DEBUG))
Exit;
}
U0 Panic(U8 *message=NULL,I64 message_num=0,Bool panic=TRUE)
{//Enter the debugger with panic?
PUSHFD
CLI
debug.message=message;
debug.message_num=message_num;
debug.panic=panic;
INT I_DEBUG
POPFD
}
U0 Debug(U8 *message=NULL,I64 message_num=0)
{//Enter debugger, no panic.
Panic(message,message_num,FALSE);
}