Files
TempleOS-Rijn/LT/Adam/Dbg.APZ
T
2018-09-08 21:45:20 +02:00

1410 lines
31 KiB
Plaintext

#help_index "Debugging"
InstructionEntry **disasm_table=NULL;
I8 disasm_table_entries=0;
U8 ins64_mask=0x0880088880;
I8 CompareInstructionEntries(InstructionEntry **tempi1,InstructionEntry **tempi2)
{
I8 i1,i2,j=0,result=0;
while (TRUE) {
if (j<(*tempi1)->opcode_cnt && j<(*tempi2)->opcode_cnt) {
i1=(*tempi1)->opcode[j];
i2=(*tempi2)->opcode[j];
result=i1-i2;
if (result) return result;
j++;
} else {
i1=(*tempi1)->opcode_cnt;
i2=(*tempi2)->opcode_cnt;
result=i1-i2;
if (result) return result;
i1=(*tempi1)->slash_value;
i2=(*tempi2)->slash_value;
result=i1-i2;
if (result) return result;
i1=(*tempi1)->flags & IEF_OP_SIZE32;
i2=(*tempi2)->flags & IEF_OP_SIZE32;
result=i1-i2;
if (result) return result;
i1=Bt(&ins64_mask,(*tempi1)->arg1) ||
Bt(&ins64_mask,(*tempi1)->arg2);
i2=Bt(&ins64_mask,(*tempi2)->arg1) ||
Bt(&ins64_mask,(*tempi2)->arg2);
result=i1-i2;
if (result) return result;
return result;
}
}
}
void LoadDisasmTable()
{
SysHashTable *h=asm_hash;
OpcodeHashEntry *temph;
InstructionEntry *tempi;
U8 cnt=0;
I8 i,j,k;
for (i=0;i<=h->mask;i++) {
temph=h->body[i];
while (temph) {
if (temph->type==HTT_OPCODE)
cnt+=temph->instruction_entry_cnt;
temph=temph->next;
}
}
disasm_table_entries=cnt;
j=0;
disasm_table=MAlloc(cnt*sizeof(void *));
for (i=0;i<=h->mask;i++) {
temph=h->body[i];
while (temph) {
if (temph->type==HTT_OPCODE) {
tempi=&temph->ins;
for (k=0;k<temph->instruction_entry_cnt;k++) {
disasm_table[j++]=tempi;
tempi+=sizeof(InstructionEntry);
}
}
temph=temph->next;
}
}
QSort(disasm_table,cnt,sizeof(void *),&CompareInstructionEntries);
}
if (!disasm_table) {
LoadDisasmTable;
LoadList("ST_INT_NAMES",
" \0 \0NMI\0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0cout\0coutln\0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0"
"f_unary_minus\0f_inc\0f_dec\0f_power\0f_mul\0f_div\0f_mod\0f_add\0"
"f_sub\0f_less\0f_greater\0f_less_equal\0f_greater_equal\0f_to_int_RAX\0f_to_double_RAX\0f_to_int_RDX\0"
"f_to_double_RDX\0\0");
}
BoolU8 PutSourceLine(void *add,U8 cnt,I1 *buf=NULL)
{
ClassStruct *tempc;
I8 i,minl,maxl,offset;
DbgInfo *dbg;
void **body;
I1 *src;
if (tempc=FindPSect(add,&offset)) {
if (dbg=tempc->debug) {
body=dbg->body;
minl=dbg->min_line;
maxl=dbg->max_line;
for (i=minl;i<=maxl;i++) {
if (*body>=add) {
if (*body<add+cnt) {
src=NewStr(tempc->source_link);
RemoveFirstSeg(src,":");
RemoveLastSeg(src,",");
if (buf)
SPrintF(buf,"$$LK-A,\"FL:%s,%d\"$$",src,i);
else
PrintF("$$LK-A,\"FL:%s,%d\"$$",src,i);
Free(src);
return TRUE;
} else
return FALSE;
}
body+=sizeof(void *);
}
}
}
return FALSE;
}
public void DasmIns(I1 *buf,I8 *add,I8 seg_size=64,I8 *branch=NULL)
//Disassembles one instruction
{
U1 *ip=*add,*bb;
U2 *ww;
U4 *dd;
U8 *dddd;
I8 disp,imm;
I8 opsize,opadd;
BoolU4 cont;
I8 i,j,k,n,m,o1,o2,a1,a2,aa1,aa2,arg1_size=0,arg2_size=0,a1_size,a2_size,
ModrM=-1,SIB=-1,scale,r1,r2,
Mod=-1,RM1=-1,RM2=-1,REX=-1,REX_r=0,REX_x=0,REX_b=0;
InstructionEntry *tempi;
OpcodeHashEntry *tempo,dummy;
I1 *a1_st,*a2_st,*bin_data_area,*bin_data_area2,
buf2[256],buf3[256],seg_overrides[40],arg1_st[256],arg2_st[256];
if (branch) *branch=-1;
if (seg_size==16) {
opsize=16;
opadd=16;
} else if (seg_size==32) {
opsize=32;
opadd=32;
} else {
opsize=32;
opadd=64;
}
*arg1_st=0;
*arg2_st=0;
a1_st=arg1_st;
a2_st=arg2_st;
*buf=0;
if (PutSourceLine(ip,1,buf))
StrCat(buf,"\r\n");
SPrintF(buf+StrLen(buf),"%16tP ",ip);
bin_data_area=buf+StrLen(buf);
for (i=0;i<6;i++) {
SPrintF(buf2,"%02X",ip[i]);
StrCat(buf,buf2);
}
StrCat(buf," ");
SPrintF(buf3,"%16tP ",ip+6);
bin_data_area2=buf3+StrLen(buf3);
for (i=6;i<12;i++) {
SPrintF(buf2,"%02X",ip[i]);
StrCat(buf3,buf2);
}
*seg_overrides=0;
cont=TRUE;
do {
switch (*ip++) {
case 0x2E: StrCat(seg_overrides,"CS:"); break;
case 0x36: StrCat(seg_overrides,"SS:"); break;
case 0x3E: StrCat(seg_overrides,"DS:"); break;
case 0x26: StrCat(seg_overrides,"ES:"); break;
case 0x64: StrCat(seg_overrides,"FS:"); break;
case 0x65: StrCat(seg_overrides,"GS:"); break;
case 0x66:
if (opsize==16)
opsize=32;
else
opsize=16;
break;
case 0x67:
if (opadd==16)
opadd=32;
else
opadd=16;
break;
case 0x40:
REX=0x40;
break;
case 0x41:
REX=0x41;
REX_b=8;
break;
case 0x42:
REX=0x42;
REX_x=8;
break;
case 0x43:
REX=0x43;
REX_b=8;
REX_x=8;
break;
case 0x44:
REX=0x44;
REX_r=8;
break;
case 0x45:
REX=0x45;
REX_b=8;
REX_r=8;
break;
case 0x46:
REX=0x46;
REX_x=8;
REX_r=8;
break;
case 0x47:
REX=0x47;
REX_b=8;
REX_x=8;
REX_r=8;
break;
case 0x48:
REX=0x48;
opsize=64;
break;
case 0x49:
REX=0x49;
REX_b=8;
opsize=64;
break;
case 0x4A:
REX=0x4A;
REX_x=8;
opsize=64;
break;
case 0x4B:
REX=0x4B;
REX_b=8;
REX_x=8;
opsize=64;
break;
case 0x4C:
REX=0x4C;
REX_r=8;
opsize=64;
break;
case 0x4D:
REX=0x4D;
REX_b=8;
REX_r=8;
opsize=64;
break;
case 0x4E:
REX=0x4E;
REX_x=8;
REX_r=8;
opsize=64;
break;
case 0x4F:
REX=0x4F;
REX_b=8;
REX_x=8;
REX_r=8;
opsize=64;
break;
default:
cont=FALSE;
}
} while (cont);
ip--;
i=0;
j=disasm_table_entries-1;
do {
k=(i+j)>>1; //binary search
tempi=disasm_table[k];
m=0;
n=0;
while (TRUE) {
if (n<tempi->opcode_cnt) {
o1=ip[n];
if (n==tempi->opcode_cnt-1 &&
tempi->flags & IEF_PLUS_OPCODE)
o1&=-8;
o2=tempi->opcode[n];
m=o1-o2;
n++;
if (m)
break;
} else {
if (tempi->slash_value<8) {
o1=(ip[n] >> 3) & 7;
o2=tempi->slash_value;
m=o1-o2;
if (!m) {
if (opsize==16) {
if (tempi->flags & IEF_OP_SIZE32)
m=-1;
} else {
if (tempi->flags & IEF_OP_SIZE16)
m=1;
}
if (!m) {
if (opsize==64||tempi->flags&IEF_NO_REX) {
if (!Bt(&ins64_mask,tempi->arg1) &&
!Bt(&ins64_mask,tempi->arg2))
m=1;
} else {
if (Bt(&ins64_mask,tempi->arg1) ||
Bt(&ins64_mask,tempi->arg2))
m=-1;
}
}
}
break;
} else {
m=0;
if (opsize==16) {
if (tempi->flags & IEF_OP_SIZE32)
m=-1;
} else {
if (tempi->flags & IEF_OP_SIZE16)
m=1;
}
if (!m) {
a1=tempi->arg1;
a2=tempi->arg2;
if (opsize==64) {
if (!Bt(&ins64_mask,a1) &&
!Bt(&ins64_mask,a2) &&
!(a2==ARGT_NO &&
(a1>=ARGT_UIMM8 && a1<=ARGT_UIMM64 ||
a1>=ARGT_IMM8 && a1<=ARGT_IMM64 ) ))
m=1;
} else {
if (Bt(&ins64_mask,a1) ||
Bt(&ins64_mask,a2))
m=-1;
}
}
break;
}
}
}
if (m>0) {
if (k==i) {
k=j;
break;
} else
i=k;
} else if (m<0) {
if (k-i<=1) {
k=i;
break;
} else
j=k;
} else
break;
} while (TRUE);
tempi=disasm_table[k];
ip+=tempi->opcode_cnt;
tempo=tempi-(tempi->ins_entry_num*sizeof(InstructionEntry))+&dummy-&dummy.ins;
StrCat(buf,tempo->str);
a1=tempi->arg1;
a2=tempi->arg2;
aa1=a1;
aa2=a2;
StrCpy(buf2,SysTextSub(a1,"ST_ARGUMENT_TYPES"));
if (StrStr(buf2,"8")) {
arg1_size=1;
StrCat(arg1_st,"U1 ");
} else if (StrStr(buf2,"16")) {
arg1_size=2;
StrCat(arg1_st,"U2 ");
} else if (StrStr(buf2,"32")) {
arg1_size=4;
StrCat(arg1_st,"U4 ");
} else if (StrStr(buf2,"64")) {
arg1_size=8;
StrCat(arg1_st,"U8 ");
}
StrCpy(buf2,SysTextSub(a2,"ST_ARGUMENT_TYPES"));
if (StrStr(buf2,"8")) {
arg2_size=1;
StrCat(arg2_st,"U1 ");
} else if (StrStr(buf2,"16")) {
arg2_size=2;
StrCat(arg2_st,"U2 ");
} else if (StrStr(buf2,"32")) {
arg2_size=4;
StrCat(arg2_st,"U4 ");
} else if (StrStr(buf2,"64")) {
arg2_size=8;
StrCat(arg2_st,"U8 ");
}
a1_size=arg1_size;
a2_size=arg2_size;
if (tempi->flags & IEF_PLUS_OPCODE && (tempi->slash_value==SV_REGISTER ||
tempi->opcode_modifier>=OM_RB && tempi->opcode_modifier<=OM_RD)) {
ip--;
RM1=*(ip++) - tempi->opcode[tempi->opcode_cnt-1]+REX_b;
*buf2=0;
if (a1>=ARGT_R8 && a1<=ARGT_R64) {
if (a1_size==1)
SPrintF(buf2,"%Z",RM1,"ST_U1_REGS");
else if (a1_size==2)
SPrintF(buf2,"%Z",RM1,"ST_U2_REGS");
else if (a1_size==4)
SPrintF(buf2,"%Z",RM1,"ST_U4_REGS");
else if (a1_size==8)
SPrintF(buf2,"%Z",RM1,"ST_U8_REGS");
StrCat(a1_st,buf2);
} else {
if (a2_size==1)
SPrintF(buf2,"%Z",RM1,"ST_U1_REGS");
else if (a2_size==2)
SPrintF(buf2,"%Z",RM1,"ST_U2_REGS");
else if (a2_size==4)
SPrintF(buf2,"%Z",RM1,"ST_U4_REGS");
else if (a2_size==8)
SPrintF(buf2,"%Z",RM1,"ST_U8_REGS");
StrCat(a2_st,buf2);
}
}
if ((a1>=ARGT_RM8 && a1<=ARGT_RM64) ||
(a2>=ARGT_RM8 && a2<=ARGT_RM64)) {
if (a2>=ARGT_RM8 && a2<=ARGT_RM64) {
a1_st=arg2_st;
a2_st=arg1_st;
a1_size=arg2_size;
a2_size=arg1_size;
aa1=a2;
aa2=a1;
}
StrCat(a1_st,seg_overrides);
ModrM=*(ip++);
Mod=(ModrM>>6) & 3;
RM1=ModrM & 7+REX_b;
RM2=(ModrM>>3) & 7+REX_r;
if (Mod<3 && RM1&7==4) {
SIB=*(ip++);
}
if (Mod==1) {
bb=ip;
disp=*bb;
SPrintF(buf2,"%02X",disp);
StrCat(a1_st,buf2);
ip++;
}
if (Mod==2) {
dd=ip;
disp=*dd;
SPrintF(buf2,"%08X",disp);
StrCat(a1_st,buf2);
ip+=4;
}
if (tempi->slash_value<8)
RM2=-1;
else {
*buf2=0;
if (aa2==ARGT_SREG)
SPrintF(buf2,"%Z",RM2,"ST_SEG_REGS");
else if (!(aa2>=ARGT_IMM8 && aa2<=ARGT_IMM64) &&
!(aa2>=ARGT_UIMM8 && aa2<=ARGT_UIMM64)) {
if (a2_size==1)
SPrintF(buf2,"%Z",RM2,"ST_U1_REGS");
else if (a2_size==2)
SPrintF(buf2,"%Z",RM2,"ST_U2_REGS");
else if (a2_size==4)
SPrintF(buf2,"%Z",RM2,"ST_U4_REGS");
else if (a2_size==8)
SPrintF(buf2,"%Z",RM2,"ST_U8_REGS");
}
StrCat(a2_st,buf2);
}
if (RM1&7==5 && Mod==0) {
dd=ip;
disp=*dd;
ip+=4;
if (disp>MAX_I4)
disp|=0xFFFFFFFF00000000;
if (seg_size==64) {
disp+=ip;
if (aa2==ARGT_IMM8 || aa2==ARGT_UIMM8)
disp++;
else if (aa2==ARGT_IMM16 || aa2==ARGT_UIMM16)
disp+=2;
else if (aa2==ARGT_IMM32 || aa2==ARGT_UIMM32)
disp+=4;
else if (aa2==ARGT_IMM64 || aa2==ARGT_UIMM64)
disp+=8;
}
SPrintF(buf2,"[%X] ",disp);
StrCat(a1_st,buf2);
RM1=-1;
} else {
if (Mod<3) {
if (RM1&7==4) {
RM1=-1;
r1=SIB & 7+REX_b;
r2=(SIB >> 3) & 7+REX_x;
scale=(SIB >> 6) &3;
if (scale==3)
scale=8;
else if (scale==2)
scale=4;
else if (scale==1)
scale=2;
else
scale=1;
if (r1&7==5 && Mod==0) {
dd=ip;
disp=*dd;
SPrintF(buf2,"%08X",disp);
StrCat(a1_st,buf2);
ip+=4;
if (seg_size!=64)
SPrintF(buf2,"[%Z*%d]",r2,"ST_U4_REGS",scale);
else
SPrintF(buf2,"[%Z*%d]",r2,"ST_U8_REGS",scale);
StrCat(a1_st,buf2);
} else {
if (seg_size!=64)
SPrintF(buf2,"[%Z+%Z*%d]",r1,"ST_U4_REGS",
r2,"ST_U4_REGS",scale);
else
SPrintF(buf2,"[%Z+%Z*%d]",r1,"ST_U8_REGS",
r2,"ST_U8_REGS",scale);
StrCat(a1_st,buf2);
}
} else {
*buf2=0;
if (opadd==16)
SPrintF(buf2,"[%Z]",RM1,"ST_U2_REGS");
else if (opadd==32)
SPrintF(buf2,"[%Z]",RM1,"ST_U4_REGS");
else
SPrintF(buf2,"[%Z]",RM1,"ST_U8_REGS");
StrCat(a1_st,buf2);
}
} else {
*buf2=0;
if (a1_size==1)
SPrintF(buf2,"%Z",RM1,"ST_U1_REGS");
else if (a1_size==2)
SPrintF(buf2,"%Z",RM1,"ST_U2_REGS");
else if (a1_size==4)
SPrintF(buf2,"%Z",RM1,"ST_U4_REGS");
else if (a1_size==8)
SPrintF(buf2,"%Z",RM1,"ST_U8_REGS");
StrCat(a1_st,buf2);
}
}
}
if (a1>=ARGT_MOFFS8 && a1<=ARGT_MOFFS64) {
StrCat(arg1_st,seg_overrides);
if (arg1_size==1) {
bb=ip;
disp=*bb;
ip++;
SPrintF(buf2,"[%X]",disp);
StrCat(arg1_st,buf2);
} else if (opadd==16) {
ww=ip;
disp=*ww;
ip+=2;
SPrintF(buf2,"[%X]",disp);
StrCat(arg1_st,buf2);
} else {
dd=ip;
disp=*dd;
ip+=4;
SPrintF(buf2,"[%X]",disp);
StrCat(arg1_st,buf2);
}
}
if (a2>=ARGT_MOFFS8 && a2<=ARGT_MOFFS64) {
StrCat(arg2_st,seg_overrides);
if (arg2_size==1) {
bb=ip;
disp=*bb;
ip++;
SPrintF(buf2,"[%X]",disp);
StrCat(arg2_st,buf2);
} else if (opadd==16) {
ww=ip;
disp=*ww;
ip+=2;
SPrintF(buf2,"[%X]",disp);
StrCat(arg2_st,buf2);
} else {
dd=ip;
disp=*dd;
ip+=4;
SPrintF(buf2,"[%X]",disp);
StrCat(arg2_st,buf2);
}
}
switch (a1) {
case ARGT_IMM8:
case ARGT_UIMM8:
bb=ip;
imm=*bb;
SPrintF(buf2,"%02X",imm);
StrCat(arg1_st,buf2);
if (tempi->opcode[0]==0xCD) {
StrCat(arg1_st," ");
StrCat(arg1_st,SysTextSub(imm,"ST_INT_NAMES"));
}
ip++;
break;
case ARGT_IMM16:
case ARGT_UIMM16:
ww=ip;
imm=*ww;
SPrintF(buf2,"%04X",imm);
StrCat(arg1_st,buf2);
ip+=2;
break;
case ARGT_IMM32:
case ARGT_UIMM32:
dd=ip;
imm=*dd;
SPrintF(buf2,"%08X",imm);
StrCat(arg1_st,buf2);
ip+=4;
break;
case ARGT_IMM64:
case ARGT_UIMM64:
dddd=ip;
imm=*dddd;
SPrintF(buf2,"%016X",imm);
StrCat(arg1_st,buf2);
ip+=8;
break;
case ARGT_REL8:
bb=ip;
disp=*bb;
if (disp>MAX_I1)
disp|=0xFFFFFFFFFFFFFF00;
ip++;
disp+=ip;
SPrintF(buf2,"%P ",disp);
if (branch) *branch=disp;
StrCat(arg1_st,buf2);
break;
case ARGT_REL16:
ww=ip;
disp=*ww;
if (disp>MAX_I2)
disp|=0xFFFFFFFFFFFF0000;
ip+=2;
disp+=ip;
SPrintF(buf2,"%P ",disp);
if (branch) *branch=disp;
StrCat(arg1_st,buf2);
break;
case ARGT_REL32:
dd=ip;
disp=*dd;
if (disp>MAX_I4)
disp|=0xFFFFFFFF00000000;
ip+=4;
disp+=ip;
SPrintF(buf2,"%P ",disp);
if (branch) *branch=disp;
StrCat(arg1_st,buf2);
break;
case ARGT_CL:
StrCat(arg1_st,"CL");
break;
case ARGT_AL:
StrCat(arg1_st,"AL");
break;
case ARGT_AX:
StrCat(arg1_st,"AX");
break;
case ARGT_EAX:
StrCat(arg1_st,"EAX");
break;
case ARGT_DX:
StrCat(arg1_st,"DX");
break;
case ARGT_SS:
StrCat(arg1_st,"SS");
break;
case ARGT_DS:
StrCat(arg1_st,"DS");
break;
case ARGT_ES:
StrCat(arg1_st,"ES");
break;
case ARGT_FS:
StrCat(arg1_st,"FS");
break;
case ARGT_GS:
StrCat(arg1_st,"GS");
break;
case ARGT_CS:
StrCat(arg1_st,"CS");
break;
}
switch (a2) {
case ARGT_IMM8:
case ARGT_UIMM8:
bb=ip;
imm=*bb;
SPrintF(buf2,"%02X",imm);
StrCat(arg2_st,buf2);
ip++;
break;
case ARGT_IMM16:
case ARGT_UIMM16:
ww=ip;
imm=*ww;
SPrintF(buf2,"%04X",imm);
StrCat(arg2_st,buf2);
ip+=2;
break;
case ARGT_IMM32:
case ARGT_UIMM32:
dd=ip;
imm=*dd;
SPrintF(buf2,"%08X",imm);
StrCat(arg2_st,buf2);
ip+=4;
break;
case ARGT_IMM64:
case ARGT_UIMM64:
dddd=ip;
imm=*dddd;
SPrintF(buf2,"%016X",imm);
StrCat(arg2_st,buf2);
ip+=8;
break;
case ARGT_CL:
StrCat(arg2_st,"CL");
break;
case ARGT_AL:
StrCat(arg2_st,"AL");
break;
case ARGT_AX:
StrCat(arg2_st,"AX");
break;
case ARGT_EAX:
StrCat(arg2_st,"EAX");
break;
case ARGT_DX:
StrCat(arg2_st,"DX");
break;
case ARGT_SS:
StrCat(arg2_st,"SS");
break;
case ARGT_DS:
StrCat(arg2_st,"DS");
break;
case ARGT_ES:
StrCat(arg2_st,"ES");
break;
case ARGT_FS:
StrCat(arg2_st,"FS");
break;
case ARGT_GS:
StrCat(arg2_st,"GS");
break;
case ARGT_CS:
StrCat(arg2_st,"CS");
break;
}
if (*arg1_st) {
StrCat(buf,"\t");
StrCat(buf,arg1_st);
}
if (*arg2_st) {
StrCat(buf,",");
StrCat(buf,arg2_st);
}
for (i=ip-*add;i<6;i++) {
bin_data_area[i<<1]=CH_SPACE;
bin_data_area[i<<1+1]=CH_SPACE;
}
for (i=ip-*add;i<12;i++) {
bin_data_area2[(i-6)<<1]=CH_SPACE;
bin_data_area2[(i-6)<<1+1]=CH_SPACE;
}
StrCat(buf,"\r\n");
if (ip-*add>6) {
StrCat(buf,buf3);
StrCat(buf,"\r\n");
}
*add=ip;
}
public U1 *Dasm(U1 *ip,U8 cnt=20,I8 seg_size=64)
//Disassembles a number of instructions.
{
I8 i;
I1 buf[1024];
for (i=0;i<cnt;i++) {
DasmIns(buf,&ip,seg_size);
cout buf;
}
return ip;
}
public I8 Dasm2(U1 *ip,U8 cnt=0x80,I8 seg_size=64)
//Disassembles a number of bytes
{
I8 i=0;
U1 *end_ip=ip+cnt;
I1 buf[1024];
while (ip<end_ip) {
DasmIns(buf,&ip,seg_size);
cout buf;
i++;
}
return i;
}
#help_index "Debugging;Utils"
#define PF_ARRAY_CNT 0x100000
U8 pf_jiffies_start,pf_jiffies_end;
U8 pf_low=0,pf_high=SYS_CS_SIZE,pf_size=PF_ARRAY_CNT;
U8 *pf_array=NULL;
void *chained_timer_routine=ext[EXT_IRQ00];
U8 pf_ptr;
#define PFM_OFF 0
#define PFM_BIN 1
#define PFM_ALL 2
I8 prof_mode=PFM_OFF;
void ProfileTimerIrq(U8 ip)
{
U8 i;
switch (prof_mode) {
case PFM_BIN:
i=(ip-pf_low) * pf_size/(pf_high-pf_low);
if (i>=0 && i<pf_size)
pf_array[i]++;
break;
case PFM_ALL:
if (pf_ptr<PF_ARRAY_CNT) {
pf_array[pf_ptr++]=ip;
if (pf_ptr==PF_ARRAY_CNT)
pf_jiffies_end=Jiffies;
}
break;
}
CallInd(chained_timer_routine,ip);
}
ext[EXT_IRQ00]=&ProfileTimerIrq;
public void ProfBin(U1 *start,U8 cnt=PF_ARRAY_CNT*3)
//Start profiler in bin mode. Profilers
//report where time is spent by checking
//the instruction pointer during the
//timer interrupt. Do a $LK,"ProfRep","MN:ProfRep"$(), (profiler report)
//after you have collected data.
{
if (cnt<PF_ARRAY_CNT)
pf_size=cnt;
else
pf_size=PF_ARRAY_CNT;
pf_low=start;
pf_high=start+cnt;
if (!pf_array)
pf_array=AMAlloc(sizeof(U8)*PF_ARRAY_CNT);
MemSet(pf_array,0,PF_ARRAY_CNT*sizeof(U8));
pf_jiffies_end=0;
pf_jiffies_start=Jiffies;
prof_mode=PFM_BIN;
}
public void ProfAll()
//Start profiler in record-all mode. Profilers
//report where time is spent by checking
//the instruction pointer during the
//timer interrupt. Do a $LK,"ProfRep","MN:ProfRep"$(), (profiler report)
//after you have collected data.
{
pf_ptr=0;
if (!pf_array)
pf_array=AMAlloc(sizeof(U8)*PF_ARRAY_CNT);
pf_jiffies_end=0;
pf_jiffies_start=Jiffies;
prof_mode=PFM_ALL;
}
I8 PFACompare(void **i1,void **i2)
{
return *i1-*i2;
}
public void ProfRep(U8 filter_cnt=1)
{
I8 i,ip,last_ip=pf_low,hits,mode=prof_mode;
U8 total_time,routine_total=0;
I1 buf[128],buf2[128],buf3[128],last_buf[128];
prof_mode=PFM_OFF;
if (pf_jiffies_end)
total_time=pf_jiffies_end-pf_jiffies_start;
else
total_time=Jiffies-pf_jiffies_start;
if (!total_time) total_time=1;
switch (mode) {
case PFM_BIN:
*last_buf=0;
for (i=0;i<pf_size;i++) {
ip=pf_low+i*(pf_high-pf_low)/pf_size;
SPrintF(buf,"%P",ip);
StrCpy(buf3,buf);
RemoveFirstSeg(buf3,",",buf2);
if (StrCmp(buf2,last_buf)) {
if (*last_buf && routine_total>=filter_cnt) {
PrintF("$$FG,GREEN$$%3d.%02d%% %08X:",routine_total*100/total_time,
routine_total*10000/total_time%100,routine_total);
PrintF("%s\r\n$$FG$$",last_buf);
}
StrCpy(last_buf,buf2);
routine_total=0;
}
hits=pf_array[i];
routine_total+=hits;
if (hits>=filter_cnt) {
PrintF("%3d.%02d%% %08X:",hits*100/total_time,
hits*10000/total_time%100,hits);
if (!PutSourceLine(ip,ip-last_ip+1))
PrintF("%s\r\n",buf);
else
CrLf;
last_ip=ip;
}
}
if (*last_buf && routine_total>=filter_cnt) {
PrintF("$$FG,GREEN$$%3d.%02d%% %08X:",routine_total*100/total_time,
routine_total*10000/total_time%100,routine_total);
PrintF("%s\r\n$$FG$$",last_buf);
}
break;
case PFM_ALL:
QSort(pf_array,pf_ptr,sizeof(U8),&PFACompare);
*last_buf=0;
for (i=0;i<pf_ptr;i++) {
ip=pf_array[i];
hits=0;
while (pf_array[i]==ip) {
hits++;
i++;
if (i>=pf_ptr) break;
}
SPrintF(buf,"%P",ip);
StrCpy(buf3,buf);
RemoveFirstSeg(buf3,",",buf2);
if (StrCmp(buf2,last_buf)) {
if (*last_buf && routine_total>=filter_cnt) {
PrintF("$$FG,GREEN$$%3d.%02d%% %08X:",routine_total*100/total_time,
routine_total*10000/total_time%100,routine_total);
PrintF("%s\r\n$$FG$$",last_buf);
}
StrCpy(last_buf,buf2);
routine_total=0;
}
routine_total+=hits;
if (hits>=filter_cnt) {
PrintF("%3d.%02d%% %08X:",hits*100/total_time,
hits*10000/total_time%100,hits);
if (!PutSourceLine(ip,ip-last_ip+1))
PrintF("%s\r\n",buf);
else
CrLf;
last_ip=ip;
}
}
if (*last_buf && routine_total>=filter_cnt) {
PrintF("$$FG,GREEN$$%3d.%02d%% %08X:",routine_total*100/total_time,
routine_total*10000/total_time%100,routine_total);
PrintF("%s\r\n$$FG$$",last_buf);
}
break;
}
prof_mode=mode;
}
#help_index "Debugging"
void ClassRep2(Ltf *l,I1 *class_name,U1 *d,I8 depth,U8 max_depth,U8 types=HTT_CLASS,I8 offset=0)
{
U8 i,j;
MemberListStruct *ml;
I1 ch,*s,*s2;
U4 *ptr;
U8 *ptr2;
ClassStruct *cl2,*cl=FindLocalHash(class_name,types);
if (depth>=max_depth) return;
if (!cl) {
LtfPutSExt(l,"Class Not Found.\r\n");
return;
}
if (!CheckPtr(d) || !CheckPtr(d+cl->size)) {
LtfPrintF(l,"Bad Ptr:%016X\r\n",d);
return;
}
LtfPrintF(l,"Class:\"%s\"\r\n",class_name);
ml=cl->member_list;
while (ml) {
cl2=ml->member_class;
ptr=d+ml->offset;
LtfPrintF(l,"%08X ",ptr+offset); //TODO
j=cl2->ptr_cnt;
while (cl2->return_class)
cl2=cl2->return_class;
cl2-=cl2->ptr_cnt*sizeof(ClassStruct);
if (cl2->type & HTT_INTERNAL_TYPE) {
LtfPrintF(l,"$$FG,GREEN$$%-20ts:$$FG$$",ml->str);
if (!j && ml->cnt==0) {
switch (cl2->sub_type) {
case IT_I1:
LtfPrintF(l,"%02X '%c'",ptr->u1[0],ptr->u1[0]);
break;
case IT_U1:
LtfPrintF(l,"%02X",ptr->u1[0]);
break;
case IT_I2:
LtfPrintF(l,"%04X",ptr->u2[0]);
break;
case IT_U2:
LtfPrintF(l,"%04X",ptr->u2[0]);
break;
case IT_I4:
LtfPrintF(l,"%08X",*ptr);
break;
case IT_U4:
LtfPrintF(l,"%08X",*ptr);
break;
case IT_DOUBLE:
ptr2=ptr;
LtfPrintF(l,"%16g",*ptr2);
break;
default:
ptr2=ptr;
LtfPrintF(l,"%016X",*ptr2);
break;
}
} else if ((j==1 || ml->cnt) &&
cl2->sub_type==IT_I1) {
if (j==1) {
if (CheckPtr(*ptr)) {
s2=MStrUtil(*ptr,SU_SAFE_DOLLAR);
LtfPrintF(l,"\"%40ts\"",s2);
Free(s2);
}
} else {
if (ml->cnt<40)
s=ptr+ml->cnt;
else
s=ptr+40;
ch=*s;
*s=0;
s2=MStrUtil(ptr,SU_SAFE_DOLLAR);
LtfPrintF(l,"\"%s\"",s2);
Free(s2);
*s=ch;
}
} else if (ml->cnt>0 && ml->cnt<=32 && !j) {
for (i=0;i<ml->cnt;i++) {
switch (cl2->sub_type) {
case IT_I1:
LtfPrintF(l,"%02X '%c' ",ptr->u1[0],ptr->u1[0]);
ptr+=1;
break;
case IT_U1:
LtfPrintF(l,"%02X ",ptr->u1[0]);
ptr+=1;
break;
case IT_I2:
LtfPrintF(l,"%04X ",ptr->u2[0]);
ptr+=2;
break;
case IT_U2:
LtfPrintF(l,"%04X ",ptr->u2[0]);
ptr+=2;
break;
case IT_I4:
LtfPrintF(l,"%08X ",*ptr);
ptr+=4;
break;
case IT_U4:
LtfPrintF(l,"%08X ",*ptr);
ptr+=4;
break;
case IT_DOUBLE:
ptr2=ptr;
LtfPrintF(l,"%16g ",*ptr2);
ptr+=8;
break;
default:
ptr2=ptr;
LtfPrintF(l,"%016X ",*ptr2);
ptr+=8;
break;
}
}
} else
LtfPrintF(l,"%016X",*ptr);
LtfPutSExt(l,"\r\n");
} else {
if (depth<2) {
if (j==1 && !CheckPtr(*ptr))
LtfPrintF(l,"%-20ts:%016X\r\n",ml->str,*ptr);
else {
LtfPrintF(l,"$$TR,\"%s\"$$\r\n",ml->str);
LtfPutSExt(l,"$$ID,2$$");
if (!j)
ClassRep2(l,cl2->str,ptr,depth+1,max_depth);
else if (j==1)
ClassRep2(l,cl2->str,*ptr,depth+1,max_depth);
LtfPutSExt(l,"$$ID,-2$$");
}
} else
LtfPrintF(l,"%-20ts\r\n",ml->str);
}
ml=ml->next;
}
}
public void ClassRep(I1 *class_name,U1 *d,I8 max_depth=2,BoolU4 fun=FALSE,I8 offset=0)
//Displays members of a record
//by using the compiler's info.
{
Ltf *l;
BoolU4 old_preempt;
if (IsRaw) {
l=LtfNew;
} else {
LtfMax;
old_preempt=Preempt(OFF);
l=Fs->cur_ltf;
}
if (fun)
ClassRep2(l,class_name,d,0,max_depth,HTT_FUNCTION,offset);
else
ClassRep2(l,class_name,d,0,max_depth,HTT_CLASS,offset);
LtfPutSExt(l,"\r\n");
LtfRecalc(l);
if (IsRaw) {
LtfDump(l,150000);
LtfDel(l);
} else
Preempt(old_preempt);
}
void RawClassRep(I1 *st,U1 *rbp=NULL,I8 max_depth,BoolU8 is_function,I8 offset=0)
{
BoolU4 old_raw=Raw(ON);
dc_col=0;
ClassRep(st,rbp,max_depth,is_function,offset);
old_raw=Raw(old_raw);
}
void UpdateRegVarImg(ClassStruct *cl,U1 *d,TssStruct *tss)
{
MemberListStruct *ml;
ClassStruct *cl2;
ml=cl->member_list;
while (ml) {
if (ml->register>=CREG_RAX) {
cl2=ml->member_class;
while (cl2->return_class)
cl2=cl2->return_class;
MemCpy(d+ml->offset,&tss->rax+ml->register*8,cl2->size);
}
ml=ml->next;
}
}
public void FunRep(I1 *st,U1 *rbp=NULL,I8 max_depth=2,TssStruct *tss=NULL)
//Shows names and values of a function's
//local variables using info the compiler
//has.
{
I8 size;
void *img;
ClassStruct *tempc=FindLocalHash(st,HTT_FUNCTION);
MemberListStruct *tempm;
if (tempc) {
if (rbp) {
if (tss) {
size=tempc->parameter_cnt*8-tempc->size+16;
img=MAlloc(size);
MemCpy(img,rbp+tempc->size,size);
UpdateRegVarImg(tempc,img-tempc->size,tss);
ClassRep(st,img-tempc->size,max_depth,TRUE,rbp-img+tempc->size);
Free(img);
} else
ClassRep(st,rbp,max_depth,TRUE);
} else {
tempm=tempc->member_list;
while (tempm) {
if (tempm->register==-1)
PrintF("%08tX %s\r\n",tempm->offset,tempm->str);
else
PrintF("%08Z %s\r\n",tempm->register,"ST_U8_REGS",tempm->str);
tempm=tempm->next;
}
PrintF("%08tX Stack Size\r\n",tempc->size);
}
}
}
public void DasmFun(I1 *st)
{
ClassStruct *tempc=FindLocalHash(st,HTT_FUNCTION);
DbgInfo *tempd;
if (tempc) {
FunRep(st);
if (tempd=tempc->debug) {
Dasm2(tempc->executable_address,
tempd->body[tempd->max_line-tempd->min_line+1]-
tempc->executable_address);
} else
Dasm(tempc->executable_address);
}
}
#help_index "Debugging/Breakpoints"
SysBpt *FindBpt(TssStruct *tss,U1 *a,U8 flags=ALL_MASK,BoolU4 remove=FALSE)
{//Removes
SysBpt *result=NULL;
U8 old_flags=GetFlags;
SysBpt *tempb,*tempb1,*tempb2;
Cli;
tempb1=&tss->bpt_list;
tempb=tss->bpt_list;
while (tempb) {
tempb2=tempb->next;
if (tempb->address==a && tempb->flags & flags) {
result=tempb;
if (remove)
tempb1->next=tempb2;
else
tempb1=&tempb->next;
} else
tempb1=&tempb->next;
tempb=tempb2;
}
SetFlags(old_flags);
return result;
}
public BoolU4 SBpt(TssStruct *tss,U1 *a,U8 flags=SBPTF_BPT) //set Bpt
//Sets a breakpoint
//Honestly, I never use this. I put
//output statements to debug, partly
//because breakpoints don't work well.
//You can configure your $FG,2$Fault.CPZ$FG$ file
//in your $FG,2$HOME$FG$ directory to assist debuggting.
{
U8 old_flags=GetFlags;
BoolU4 result=TRUE;
SysBpt *tempb;
Cli;
if (!(tempb=FindBpt(tss,a,flags,FALSE))) {
tempb=MAlloc(sizeof(SysBpt),tss);
tempb->address=a;
tempb->b=*a;
tempb->flags=flags;
result=FALSE;
tempb->next=tss->bpt_list;
tss->bpt_list=tempb;
if (tss==Fs)
*a=0xCC;
}
SetFlags(old_flags);
return result;
}
public BoolU4 RBpt(TssStruct *tss,U1 *a,U8 flags=ALL_MASK)
//Resets (removes) one breakpoint
{
U8 old_flags=GetFlags;
BoolU4 result=FALSE;
SysBpt *tempb;
Cli;
if (tempb=FindBpt(tss,a,flags,TRUE)) {
result=TRUE;
Free(tempb,tss);
}
SetFlags(old_flags);
return result;
}
BoolU8 DBpt(TssStruct *tss,U1 *a,U8 flags=ALL_MASK) //disable one Bpt
{ //used for continuing after a bpt
U8 old_flags=GetFlags;
BoolU4 result=FALSE;
SysBpt *tempb;
Cli;
if (tempb=FindBpt(tss,a,flags,FALSE)) {
Bts(&tempb->flags,SBPTf_DISABLE);
result=TRUE;
}
SetFlags(old_flags);
return result;
}
public void CBpt(TssStruct *tss,U8 flags=ALL_MASK) //clear Bpts
//Clear break-point
{
U1 *a;
U8 old_flags=GetFlags;
SysBpt *tempb,*tempb1,*tempb2;
Cli;
tempb=tss->bpt_list;
tempb1=&tss->bpt_list;
while (tempb) {
tempb2=tempb->next;
if (tempb->flags & flags) {
a=tempb->address;
if (tss==Fs)
*a=tempb->b;
Free(tempb,tss);
tempb1->next=tempb2;
} else
tempb1=&tempb->next;
tempb=tempb2;
}
SetFlags(old_flags);
}
public void Go()
//Continue after breakpoint
{
TssStruct *tss=Fs->parent_tss;
void *rip=&tss->rip;
if (!Btr(&tss->task_flags,TSSf_DISABLE_BPTS)) {
*rip-=1;
if (!DBpt(tss,*rip))
*rip+=1;
}
Btr(&tss->rflags,8);
Btr(&tss->task_flags,TSSf_SUSPENDED);
Exit;
}
public void Step()
//Execute single assembly instruction
//and stop.
{
TssStruct *tss=Fs->parent_tss;
void *rip=&tss->rip;
if (!Bts(&tss->task_flags,TSSf_DISABLE_BPTS)) {
*rip-=1;
if (!DBpt(tss,*rip))
*rip+=1;
}
Bts(&tss->rflags,8);
Btr(&tss->task_flags,TSSf_SUSPENDED);
Exit;
}
#help_index ""