Trivial Solutions The LoseThos 64-bit PC Operating System File:/LT/Opt/IDE.APZ This, and all LoseThos files, are public domain. Do whatever you like. God is watching; God is just; God is never out-done in generosity. He talks! LoseThos code compiles with the 64-bit LoseThos compiler/assembler I wrote. Boot the LoseThos CD and you can compile it. Not in Kansas anymore! Click here for preliminary compiler information you need. #help_index "Debugging" #define IDET_GO 1 #define IDET_STEP_INTO 2 #define IDET_STEP_OVER 3 class IDEStruct { I64 type; U0 *cur_line,*next_line; U0 *call_bpt; BoolI8 existing_bpt; }; U0 IDEWaitParent() { TaskStruct *task=Fs->parent_task; while (!Bt(&task->task_flags,TASKf_SUSPENDED) && !Bt(&task->task_flags,TASKf_IDLE) && !Bt(&task->rflags,RFLAGS_SINGLE_STEP)) Yield; } public ClassStruct *DbgFunFind(Ltf *l,I64 line_offset=0) { U8 st[256],*filename=l->filename.name; I64 line=l->cur_entry->y+1+line_offset; SysHashTable *h=Fs->hash_table; SrcSymHashEntry *temph; DbgInfo *dbg; while (h) { temph=h->next_added; while (temph!=h) { if (temph->h.type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) dbg=temph->debug; else dbg=NULL; if (dbg) { StrCpy(st,temph->src_link); StrFirstRem(st,":"); StrLastRem(st,","); if (!StrCmp(st,filename)) { if (dbg->min_line<=line<=dbg->max_line) return temph; } } temph=temph->h.next_added; } h=h->next; } return NULL; } U0 WatchLocals() { BoolI8 old_preempt=Preempt(OFF); TaskStruct *task=Fs->parent_task,*dbg_task; Ltf *l; ClassStruct *tempc,*tempc1; U64 sc,ch; LTDate timeout; U0 **rbp,**ptr; I64 offset,ip; while (TRUE) { IDEWaitParent; if (!TaskValidate(dbg_task=task->dbg_task)) Exit; if (ScanKey(&ch,&sc,TRUE)) { timeout=BootTime+LTDATE_FREQ*4; do { if (ch==CH_CTRLQ || ch==CH_ESC) Exit; if (ScanKey(&ch,&sc,TRUE)) timeout=BootTime+LTDATE_FREQ*4; WinSync; } while (BootTime<timeout); } else { IDEWaitParent; if (!TaskValidate(dbg_task=task->dbg_task)) Exit; LtfDblBufStart; if (l=LtfCur(dbg_task)) { if (tempc=DbgFunFind(l,0)) { PutS("$WW,1$"); rbp=task->rbp; ip=task->rip; while (TRUE) { tempc1=PSectFind(ip,&offset); break; //TODO: load reg vars for higher level subroutines if (tempc==tempc1) break; else { if (rbp>=*rbp) break; ptr=rbp+1; rbp=*rbp; ip=*ptr; if (!ChkOnStk(rbp,task)) break; } } if (tempc==tempc1) FunRep(tempc->s.h.str,rbp,1,task); } } LtfDblBufEnd; WinSync; } } Preempt(old_preempt); } public U0 IDE(U8 *filename) //Spawns a child process which has //access to parents syms. Can be used //to debug parent. { TaskStruct *task; U8 *fn1=DftExt(filename,"CPZ"), *fn2=FileNameAbs(fn1); if (PopUpCancelOk("$BK,1$$FG,RED$LoseThos IDE Debugger$FG$$BK,0$\r\n" "Do not use this on files that run when included.\r\n" "\r\nTo use:\r\n" " 1) Set a break-point in the editor window.\r\n" " 2) Run program from cmd line.\r\n\r\n" "$FG,GREEN$F5$FG$\t\tGo\r\n" "$FG,GREEN$F10$FG$\t\tStep Over\r\n" "$FG,GREEN$F11$FG$\t\tStep Into\r\n" "$FG,GREEN$F9$FG$\t\tToggle Break Point\r\n" "$FG,GREEN$SHIFT-F9$FG$\tClear All Break Points\r\n", "\r\n\r\n\r\nNote: I don't use this debugger because\r\n" "I'm always doing multitasking stuff, \r\n" "kernel stuff and multicore stuff. Also,\r\n" "you can't debug code in the window\r\n" "manager callbacks. It works on really\r\n" "simple stuff, sort-of.\r\n\r\n" "I recommend making use of:\r\n" "$LK,\"progress1\",\"MN:progress1\"$-$LK,\"progress4\",\"MN:progress4\"$, -- glbl I64 vars shown on wallpaper\r\n" "$LK,\"DbgNum\",\"MN:DbgNum\"$() $LK,\"DbgStr\",\"MN:DbgStr\"$() $LK,\"DbgAdd\",\"MN:DbgAdd\"$() -- raw text output for a time\r\n" "$LK,\"Beep\",\"MN:Beep\"$() $LK,\"Snd\",\"MN:Snd\"$() -- sound\r\n" "$LK,\"AdamLog\",\"MN:AdamLog\"$() $LK,\"AdamErr\",\"MN:AdamErr\"$() -- printf to adam task's window\r\n" "$LK,\"SysDbg\",\"MN:SysDbg\"$() and $LK,\"IsSysDbg\",\"MN:IsSysDbg\"$() -- just a flag\r\n" "$FG,RED$dbgo$FG$ and $FG,RED$dbgoln$FG$ are just aliases for $FG,GREEN$cout$FG$ that you\r\n" "search for when cleaning-up.\r\n\r\n")) { Fs->win_top=2; Fs->win_bottom=TEXT_ROWS-2; Fs->win_left=1; Fs->win_right=TEXT_COLS>>1-1; TaskDerivedValsUpdate; LBts(&Fs->display_flags,DISPLAYf_CHILDREN_NOT_ON_TOP); task=Spawn(&UserCmdLine,NULL,"Debug",Fs); TaskWaitIdle(task); task->win_top=12; task->win_bottom=TEXT_ROWS-2; task->win_left=TEXT_COLS>>1+1; task->win_right=TEXT_COLS-2; TaskDerivedValsUpdate(task); XTalk(task,"Ed(\"%s\");\r",fn2); Fs->dbg_task=task; task=Spawn(&UserCmdLine,NULL,"Watch",Fs); TaskWaitIdle(task); task->win_top=2; task->win_bottom=10; task->win_left=TEXT_COLS>>1+1; task->win_right=TEXT_COLS-2; TaskDerivedValsUpdate(task); XTalk(task,"WatchLocals;\r"); ExeFile(fn2); Free(fn1); Free(fn2); } } #help_index "Debugging/Breakpoints" I64 IDELineAdd(DbgInfo *dbg,I64 line) { I64 max=dbg->max_line-dbg->min_line; line-=dbg->min_line; if (line<0) return IDELineAdd(dbg,dbg->min_line); while (!dbg->body[line] && line<=max) line++; return dbg->body[line]; } I64 IDERIPLineNum(Ltf *l,U0 *rip) { U8 st[256],*filename=l->filename.name; I64 line; SysHashTable *h=Fs->hash_table; ClassStruct *tempc; DbgInfo *dbg; while (h) { tempc=h->next_added; while (tempc!=h) { if (tempc->s.h.type&HTT_FUN) { if (dbg=tempc->s.debug) { StrCpy(st,tempc->s.src_link); StrFirstRem(st,":"); StrLastRem(st,","); if (!StrCmp(st,filename)) { for (line=dbg->min_line;line<=dbg->max_line;line++) if (rip>=IDELineAdd(dbg,line) && rip<IDELineAdd(dbg,line+1)) return line; } } } tempc=tempc->s.h.next_added; } h=h->next; } return -1; } U0 IDESetStepRange(Ltf *l) { U8 st[256],*filename=l->filename.name; I64 line=l->cur_entry->y+1; SysHashTable *h=Fs->hash_table; ClassStruct *tempc; IDEStruct *tempi=NamedFramePtr("IDEFrame"); DbgInfo *dbg; while (h) { tempc=h->next_added; while (tempc!=h) { if (tempc->s.h.type&HTT_FUN) { if (dbg=tempc->s.debug) { StrCpy(st,tempc->s.src_link); StrFirstRem(st,":"); StrLastRem(st,","); if (!StrCmp(st,filename)) { if (dbg->min_line<=line<=dbg->max_line) { tempi->cur_line =IDELineAdd(dbg,line); tempi->next_line=IDELineAdd(dbg,line+1); return; } } } } tempc=tempc->s.h.next_added; } h=h->next; } } U0 IDEToggleBpt(Ltf *l) { //F9 U8 st[512],*filename=l->filename.name; I64 a,line=l->cur_entry->y+1; BoolI8 unlock; SysHashTable *h=Fs->hash_table; ClassStruct *tempc; DbgInfo *dbg; LtfEntry *ll; while (h) { tempc=h->next_added; while (tempc!=h) { if (tempc->s.h.type&HTT_FUN) { if (dbg=tempc->s.debug) { StrCpy(st,tempc->s.src_link); StrFirstRem(st,":"); StrLastRem(st,","); if (!StrCmp(st,filename)) { if (dbg->min_line<=line<=dbg->max_line) { a=IDELineAdd(dbg,line); unlock=LtfLock(l); ll=l->cur_entry; while (ll->last->btype!=LTFT_CR && ll->last->btype!=LTFT_SOFT_CR && ll->last!=l) ll=ll->last; l->cur_entry=ll; l->cur_data_col=ll->min_col; if (!BptR(Fs->parent_task,a)) { BptS(Fs->parent_task,a); LtfPutS(l,"$BP$"); } else { if (ll->btype==LTFT_BPT) { l->cur_entry=ll->next; l->cur_data_col=l->cur_entry->min_col; LtfDelEntry(l,ll); } } if (unlock) LtfUnlock(l); LtfGoToLineNum(l,line); return; } } } } tempc=tempc->s.h.next_added; } h=h->next; } } U0 IDEClearAllBpts(Ltf *l) { //SHIFT-F9 LtfEntry *ll,*ll2; BoolI8 unlock; IDEWaitParent; BptsR(Fs->parent_task); unlock=LtfLock(l); ll=l->root.next; while (ll!=l) { ll2=ll->next; if (ll->btype==LTFT_BPT) { if (l->cur_entry==ll) { l->cur_entry=ll->next; l->cur_data_col=l->cur_entry->min_col; } LtfDelEntry(l,ll); } ll=ll2; } if (unlock) LtfUnlock(l); } U0 IDEGo() //Continue after breakpoint { //F5 TaskStruct *task=Fs->parent_task; IDEStruct *tempi=NamedFramePtr("IDEFrame"); if (!tempi) { tempi=CAlloc(sizeof(IDEStruct)); NamedFramePtrAdd("IDEFrame",tempi); } IDEWaitParent; LBts(&task->task_flags,TASKf_DISABLE_BPTS); tempi->cur_line=task->rip; tempi->type=IDET_GO; LBts(&task->rflags,RFLAGS_SINGLE_STEP); LBtr(&task->task_flags,TASKf_SUSPENDED); } U0 IDEStepOver(Ltf *l) { //F10 TaskStruct *task=Fs->parent_task; I64 line; U8 *opcode; IDEStruct *tempi=NamedFramePtr("IDEFrame"); if (!tempi) { tempi=CAlloc(sizeof(IDEStruct)); NamedFramePtrAdd("IDEFrame",tempi); } IDEWaitParent; line=IDERIPLineNum(l,task->rip); LBts(&task->task_flags,TASKf_DISABLE_BPTS); if (line>0) { LtfGoToLineNum(l,line); IDESetStepRange(l); } else { tempi->cur_line=NULL; tempi->next_line=NULL; } tempi->type=IDET_STEP_OVER; tempi->call_bpt=NULL; LBts(&task->rflags,RFLAGS_SINGLE_STEP); LBtr(&task->task_flags,TASKf_SUSPENDED); opcode=task->rip; if (*opcode==OC_CALL) { if (BptS(task,opcode+5)) { if (tempi->call_bpt!=opcode+5) tempi->existing_bpt=TRUE; } else tempi->existing_bpt=FALSE; tempi->call_bpt=opcode+5; LBtr(&task->task_flags,TASKf_DISABLE_BPTS); LBtr(&task->rflags,RFLAGS_SINGLE_STEP); } } U0 IDEStepInto(Ltf *l) { //F11 TaskStruct *task=Fs->parent_task; I64 line; IDEStruct *tempi=NamedFramePtr("IDEFrame"); if (!tempi) { tempi=CAlloc(sizeof(IDEStruct)); NamedFramePtrAdd("IDEFrame",tempi); } IDEWaitParent; line=IDERIPLineNum(l,task->rip); LBts(&task->task_flags,TASKf_DISABLE_BPTS); if (line>0) { LtfGoToLineNum(l,line); IDESetStepRange(l); } else { tempi->cur_line=NULL; tempi->next_line=NULL; } tempi->type=IDET_STEP_INTO; LBts(&task->rflags,RFLAGS_SINGLE_STEP); LBtr(&task->task_flags,TASKf_SUSPENDED); } U0 IDEEdTask(U64 dummy=0) { nounusedwarn dummy; TaskStruct *task=Fs->parent_task; U0 *rip=task->rip; U8 *st,*rip_filename,*bpt_filename; TaskStruct *ed_task=NULL,*dbg_task; IDEStruct *tempi,*tempi1; Ltf *l; SysBpt *tempb; if (rip_filename=SrcFileName(rip)) { ed_task=Spawn(&UserCmdLine,NULL,"Debug",task); TaskWaitIdle(ed_task); st=MSPrintF("Preempt(OFF);Ed(\"%s\");\r",rip_filename); XTalkWithWait(ed_task,st); Free(st); l=LtfCur(ed_task); if (TaskValidate(dbg_task=task->dbg_task)) { ed_task->win_top=dbg_task->win_top; ed_task->win_bottom=dbg_task->win_bottom; ed_task->win_left=dbg_task->win_left; ed_task->win_right=dbg_task->win_right; TaskDerivedValsUpdate(ed_task); if (tempi=NamedFramePtr("IDEFrame",dbg_task)) { tempi1=MAllocIdentical(tempi,ed_task); NamedFramePtrAdd("IDEFrame",tempi1); } Kill(dbg_task); } task->dbg_task=ed_task; tempb=task->bpt_list; while (tempb) { if (bpt_filename=SrcFileName(tempb->address)) { if (!StrCmp(rip_filename,bpt_filename)) { LtfGoToLineNum(l,SrcLineNum(tempb->address)); LtfPutS(l,"$BP$"); } Free(bpt_filename); } tempb=tempb->next; } LtfGoToLineNum(l,SrcLineNum(rip)); Free(rip_filename); StrCpy(ed_task->task_title,"Debug Task"); } } U0 IDEResumeDbg() { TaskStruct *dbg_task=Fs->dbg_task; IDEStruct *tempi=NamedFramePtr("IDEFrame",dbg_task); U8 *opcode; if (!tempi) { Spawn(&IDEEdTask,NULL,"Resume Dbg",Fs); LBts(&Fs->task_flags,TASKf_SUSPENDED); } else switch (tempi->type) { case IDET_GO: if (tempi->cur_line) { LBtr(&Fs->task_flags,TASKf_DISABLE_BPTS); LBtr(&Fs->rflags,RFLAGS_SINGLE_STEP); if (Fs->rip==tempi->cur_line) {//Jmp to self tempi->cur_line=NULL; Spawn(&IDEEdTask,NULL,"Resume Dbg",Fs); LBts(&Fs->task_flags,TASKf_SUSPENDED); } else tempi->cur_line=NULL; } else { Spawn(&IDEEdTask,NULL,"Resume Dbg",Fs); LBts(&Fs->task_flags,TASKf_SUSPENDED); } break; case IDET_STEP_INTO: if (!tempi->cur_line || Fs->rip<tempi->cur_line || Fs->rip>=tempi->next_line) { Spawn(&IDEEdTask,NULL,"Resume Dbg",Fs); LBts(&Fs->task_flags,TASKf_SUSPENDED); } else LBtr(&Fs->task_flags,TASKf_SUSPENDED); break; case IDET_STEP_OVER: LBts(&Fs->rflags,RFLAGS_SINGLE_STEP); LBts(&Fs->task_flags,TASKf_DISABLE_BPTS); if (Fs->rip==tempi->call_bpt) { if (!tempi->existing_bpt) BptR(Fs,Fs->rip,FALSE); tempi->call_bpt=NULL; } if (!tempi->cur_line || Fs->rip<tempi->cur_line || Fs->rip>=tempi->next_line) { Spawn(&IDEEdTask,NULL,"Resume Dbg",Fs); LBts(&Fs->task_flags,TASKf_SUSPENDED); } else { opcode=Fs->rip; if (*opcode==OC_CALL) { if (BptS(Fs,opcode+5,FALSE)) { if (tempi->call_bpt!=opcode+5) tempi->existing_bpt=TRUE; } else tempi->existing_bpt=FALSE; tempi->call_bpt=opcode+5; LBtr(&Fs->task_flags,TASKf_DISABLE_BPTS); LBtr(&Fs->rflags,RFLAGS_SINGLE_STEP); } LBtr(&Fs->task_flags,TASKf_SUSPENDED); } break; } } ext[EXT_RESUME_DBG]=&IDEResumeDbg; #help_index ""