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; }