I64 HasLower(U8 *src)
{
I64 ch;
while (ch=*src++)
if ('a'<=ch<='z')
return TRUE;
return FALSE;
}
U0 HashFunSegFind(CHashTable *h,U8 *addr,
Bool *_has_lower,U64 *_best,CHash **_res)
{
Bool *has_lower=*_has_lower;
CHashExport *tmpex;
U64 i,j,best=*_best;
CHash *res=*_res;
for (i=0;i<=h->mask;i++) {
tmpex=h->body[i];
while (tmpex) {
j=0;
if (tmpex->type&HTT_FUN) {
if (!Bt(&tmpex(CHashFun *)->flags,Cf_EXTERN) &&
!Bt(&tmpex(CHashFun *)->flags,Ff_INTERNAL))
j=tmpex(CHashFun *)->exe_addr;
} else if (tmpex->type&HTT_EXPORT_SYS_SYM)
j=tmpex->val;
if (j) {
j=addr(I64)-j;
if (0<=j<=best) {
if (tmpex->type&HTT_EXPORT_SYS_SYM) {
if (j<best || j==best && !has_lower) {
has_lower=HasLower(tmpex->str);
best=j;
res=tmpex;
}
} else if (tmpex->type&HTT_FUN) {
if (j<best || j==best &&
(res && res->type&HTT_EXPORT_SYS_SYM||!has_lower)) {
has_lower=HasLower(tmpex->str);
best=j;
res=tmpex;
}
}
}
}
tmpex=tmpex->next;
}
}
*_has_lower=has_lower;
*_best=best;
*_res =res;
}
CHash *FunSegFind(U8 *addr,I64 *_offset)
{//See Hash.
CHash *res=NULL;
Bool has_lower=FALSE;
CTask *task;
CHashTable *h;
CCPU *c;
U64 i,best=0xFFFF;
if (!ChkCodePtr(addr)) {
*_offset=best;
return NULL;
}
if (IsDbgMode)
for (i=0;i<mp_cnt;i++) {
c=&cpu_structs[i];
task=c->seth_task;
do {
if (!TaskValidate(task)) goto fs_abort_task;
h=task->hash_table;
while (h) {
HashFunSegFind(h,addr,&has_lower,&best,&res);
h=h->next;
}
task=task->next_task;
} while (task!=c->seth_task);
fs_abort_task:
}
else {
h=Fs->hash_table;
while (h) {
HashFunSegFind(h,addr,&has_lower,&best,&res);
h=h->next;
}
}
*_offset=best;
return res;
}
U0 FunSegCacheAdd(CHash *tmps,U8 *addr)
{
I64 i;
CDbgInfo *dbg_info;
CFunSegCache *tmpfsc;
if (tmps && tmps->type&HTT_FUN &&
(dbg_info=tmps(CHashFun *)->dbg_info)) {
lock i=dbg.fun_seg_cache_index++;
tmpfsc=&dbg.fun_seg_cache[i&(FUN_SEG_CACHE_SIZE-1)];
tmpfsc->base=dbg_info->body[0];
if (addr<tmpfsc->base)
tmpfsc->base=addr;
tmpfsc->limit=dbg_info->body[dbg_info->max_line+1-dbg_info->min_line];
if (addr>=tmpfsc->limit)
tmpfsc->limit=addr+1;
i=MinI64(StrLen(tmps->str),FUN_SEG_CACHE_STR_LEN-1);
MemCpy(tmpfsc->str,tmps->str,i);
tmpfsc->str[i]=0;
tmpfsc->time_stamp=tS;
}
}
U8 *FunSegCacheFind(U8 *addr,I64 *_offset)
{
I64 i;
F64 timeout;
CFunSegCache *tmpfsc=dbg.fun_seg_cache;
if (addr==SYS_IDLE_PT) {
*_offset=0;
return "SYS_IDLE_PT";
} else {
timeout=tS+8.0;
for (i=0;i<FUN_SEG_CACHE_SIZE;i++,tmpfsc++)
if (tmpfsc->base<=addr<tmpfsc->limit &&
tmpfsc->time_stamp>timeout) {
*_offset=addr-tmpfsc->base;
return tmpfsc->str;
}
return NULL;
}
}
U0 StrPrintFunSeg(U8 *buf,I64 addr,I64 field_len,I64 flags)
{
I64 offset;
CHashExport *tmpex;
U8 *str,*str2;
Bool is_fun=FALSE;
if (!(flags&PRTF_TRUNCATE))
field_len=0;
if (addr) {
if (str=FunSegCacheFind(addr,&offset)) {
if (addr!=SYS_IDLE_PT)
is_fun=TRUE;
} else {
if (tmpex=FunSegFind(addr,&offset)) {
if (tmpex->type&HTT_FUN)
is_fun=TRUE;
FunSegCacheAdd(tmpex,addr);
str=tmpex->str;
}
}
if (str) {
if (offset>0xFFFF) offset=0xFFFF;
if (flags&PRTF_COMMA) {
if (is_fun) {
str2=MStrPrint("&%s",str);
if (!field_len)
StrCpy(buf,str2);
else if (flags&PRTF_LEFT_JUSTIFY && StrLen(str2)<field_len)
StrCpy(buf,str2);
else
StrPrint(buf,"%*ts",field_len,str2);
Free(str2);
} else {
if (!field_len)
StrCpy(buf,str);
else if (flags&PRTF_LEFT_JUSTIFY && StrLen(str)<field_len)
StrCpy(buf,str);
else
StrPrint(buf,"%*ts",field_len,str);
}
} else {
if (is_fun) {
str2=MStrPrint("&%s",str);
if (field_len && field_len>7) {
if (flags&PRTF_LEFT_JUSTIFY && StrLen(str2)<field_len-7)
StrPrint(buf,"%s+0x%04X",str2,offset);
else
StrPrint(buf,"%*ts+0x%04X",field_len-7,str2,offset);
} else
StrPrint(buf,"%s+0x%04X",str2,offset);
Free(str2);
} else {
if (field_len && field_len>7) {
if (flags&PRTF_LEFT_JUSTIFY && StrLen(str)<field_len-7)
StrPrint(buf,"%s+0x%04X",str,offset);
else
StrPrint(buf,"%*ts+0x%04X",field_len-7,str,offset);
} else
StrPrint(buf,"%s+0x%04X",str,offset);
}
}
return;
}
}
if (flags&PRTF_COMMA)
StrCpy(buf,".");
else if (flags&PRTF_TRUNCATE && field_len)
StrPrint(buf,"%*tX",field_len,addr);
else
StrPrint(buf,"%X",addr);
}
I64 SrcLineNum(U8 *addr,I64 cnt=1)
{//linenum for src of addr.
CHashSrcSym *tmph;
I64 cur_line,first_line,last_line,num_lines,offset;
CDbgInfo *dbg_info;
U32 *body;
U8 *src,*src2;
if (tmph=FunSegFind(addr,&offset)) {
if (tmph->type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) {
if (dbg_info=tmph->dbg_info) {
num_lines=dbg_info->max_line-dbg_info->min_line+1;
body=dbg_info->body;
//find first nonzero
first_line=0;
while (!body[first_line]) {
first_line++;
if (first_line>=num_lines)
return -1;
}
//find last nonzero
last_line=num_lines-1;
while (!body[last_line] && last_line>first_line)
last_line--;
//interpolate to guess line num
cur_line=ClampI64(ToF64(addr-body[first_line])*(last_line-first_line+1)/
(body[last_line]-body[first_line]+1),first_line,last_line);
//retreat while too high
while ((!body[cur_line] || body[cur_line]>=addr) && cur_line>first_line)
cur_line--;
//advance while to low
while ((!body[cur_line] || body[cur_line]<addr) && cur_line<last_line)
cur_line++;
if (addr<body[cur_line]+cnt)
return cur_line+dbg_info->min_line;
} else if (tmph->src_link) {
src =StrNew(tmph->src_link);
src2=StrNew(tmph->src_link);
StrLastRem(src,",",src2);
cur_line=Str2I64(src2);
Free(src);
Free(src2);
return cur_line;
}
}
}
return -1;
}
U8 *SrcFileName(U8 *addr,I64 cnt=1,CTask *mem_task=NULL)
{//MAlloc filename for src of addr.
CHashSrcSym *tmph;
I64 i,j,ii,offset,best=NULL,d,best_d;
U32 *body;
CDbgInfo *dbg_info;
U8 *src;
if ((tmph=FunSegFind(addr,&offset)) &&
tmph->type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) {
if (dbg_info=tmph->dbg_info) {
j=dbg_info->max_line-dbg_info->min_line+1;
body=dbg_info->body;
best_d=I64_MAX;
for (i=0;i<j;i++) {
if (0<body[i]<=addr<body[i]+cnt) {
ii=i+1;
while (!body[ii])
ii++;
if (addr<body[ii]) {
d=addr(I64)-body[i];
if (d<best_d) {
best_d=d;
best=tmph->src_link;
}
}
}
}
} else
best=tmph->src_link;
}
if (best) {
src=StrNew(best,mem_task);
StrFirstRem(src,":");
StrLastRem(src,",");
return src;
} else
return NULL;
}
U8 *SrcEdLink(U8 *addr,I64 cnt=1,CTask *mem_task=NULL)
{//MAlloc file,line link to src of addr.
U8 *filename,*st,*st2;
I64 linenum;
if (filename=SrcFileName(addr,cnt)) {
linenum=SrcLineNum(addr,cnt);
if (linenum<1)
linenum=1;
st2=MStrPrint("FL:%s,%d",filename,linenum);
Free(filename);
st=StrNew(st2,mem_task);
Free(st2);
return st;
}
return NULL;
}
Bool PutSrcLink(U8 *addr,I64 cnt=1,U8 *buf=NULL)
{//Put to StdOut a DolDoc file,line link to src of addr.
U8 *src;
if (src=SrcEdLink(addr,cnt)) {
if (buf)
StrPrint(buf,"$LK,\"%p\",A=\"%s\"$",addr,src);
else
"$LK,\"%p\",A=\"%s\"$",addr,src;
Free(src);
return TRUE;
} else if (buf)
*buf=0;
return FALSE;
}
Bool E(U8 *addr,I64 cnt=512,I64 edf_dof_flags=0)
{//Edit src at addr.
U8 *st;
Bool res=FALSE;
if (st=SrcEdLink(addr,cnt)) {
if (IsRaw)
res=EdLiteFileLine(st,edf_dof_flags);
else
res=Ed(st,edf_dof_flags);
Free(st);
}
return res;
}
Bool Man(U8 *st,I64 edf_dof_flags=0)
{//Owner's manual for symbol. Edit src code for symbol.
Bool res=FALSE;
U8 **st2;
CHashSrcSym *tmph;
if (IsRaw) {
if ((tmph=HashFind(st,Fs->hash_table,HTG_SRC_SYM)) && tmph->src_link)
res=EdLiteFileLine(tmph->src_link,edf_dof_flags);
} else {
st2=MStrPrint("MN:%s",st);
res=Ed(st2,edf_dof_flags);
Free(st2);
}
return res;
}