/* * Copyright (C) 1996-1998 Ilya Ryzhenkov (orangy@inetlab.com) * This file maintains some DLM API */ #include "helpdefs.h" #include "dlmimage.h" #include "dlm_sym.h" #include "dlm_rslv.h" #include "dlm.h" static const char *_dlm_version="DLM Engine version 2.02"; TDlm *_dlm_find_for_addr(unsigned long eip) { TDlm* dlm; unsigned long base; _sym_dlmsearch(); while ((dlm=_sym_dlmnext())) { base=(unsigned long)dlm->Base; if (base<=eip && base+dlm->VSize>=eip) break; } return dlm; } /* this function creates classes by their names */ void _dlm_sig_invalid_new(unsigned long eip,char *name); #define NEW_ERR _dlm_sig_invalid_new(retaddr,name); #define NEW_TOLERANCE 32 void *_dlm_new_named(unsigned long size,char *name,void*p) { static char buf[512]; void *(*stdnew)(unsigned long size); unsigned long tmp,base=0,idx,min,i,namelen,newsize=0,*szptr; char *basename,*mangle; unsigned long retaddr=*((unsigned long*)&size-1),*patchplace,patchvalue; TDlm *dlm=_dlm_find_for_addr(retaddr); if (!dlm) NEW_ERR else base=(unsigned long)dlm->Base; min=retaddr+NEW_TOLERANCE; idx=0xFFFFFFFF; for (i=0; iNumRel; i++) { tmp=dlm->Relocs[i].r_vaddr+base; if (tmp>=retaddr && tmpStrings+dlm->Symbols[dlm->Relocs[idx].r_symndx].e_name); if (strncmp(basename,"___",3)) NEW_ERR namelen=strtol(basename+3,&mangle,0); if (!namelen) NEW_ERR mangle+=namelen; sprintf(buf,"___%ld%s%s",strlen(name),name,mangle); /* now buf contains required construtor name and dlm->Relocs[idx].r_vaddr+base is a place to patch */ patchplace=(unsigned long *)(dlm->Relocs[idx].r_vaddr+base); patchvalue=(unsigned int)_sym_find_export(buf,0); if (!patchvalue) NEW_ERR /* this must be call, so assume REL32 */ *patchplace=patchvalue-base-dlm->Relocs[idx].r_vaddr-4; // printf("Patched at 0x%x to 0x%x\n",patchplace,patchvalue); /* now the code is ready to call constructor for named class instead of base class */ stdnew=(typeof(stdnew))_sym_find_export("___builtin_new",0); if (!stdnew) NEW_ERR free(basename); return stdnew(newsize); } void *_dlm_lookup(char *name) { return _sym_find_export(name,0); } int _dlm_isloaded(char *path) { return (_sym_find_dlm(path))?1:0; } unsigned long _dlm_extra_size(char *name) { int i; TDlm *dlm; void *symadr; symadr=_sym_find_export(name,0); if (!symadr) return 0; dlm=_dlm_find_for_addr((unsigned long)symadr); if (!dlm) return 0; for (i=0; iNumSect; i++) if (!strncmp(".extra",dlm->Sections[i].s_name,8)) if (dlm->Sections[i].s_vaddr+dlm->Base == symadr) return dlm->Sections[i].s_size; return 0; } void _dlm_dup_fail(char *name, TDlm* dlm); int _dlm_export_user(char *name, void *addr) { void *symaddr; symaddr=_sym_find_export(name,0); if (symaddr && ((dlmflags&DLMFLAG_DUP)==DLMFLAG_DUP_FAIL)) _dlm_dup_fail(name,(TDlm*)-1); if (!symaddr || ((dlmflags&DLMFLAG_DUP)!=DLMFLAG_DUP_IGNORE)) { if (_sym_add_export(name,addr,(TDlm*)-1)) { if (!symaddr || ((dlmflags&DLMFLAG_DUP)==DLMFLAG_DUP_OVRIDE)) _dlm_resolve_to_sym(name); } else { ERR(NOMEM); return 0; } } return 1; } int _dlm_remove_user(char *name) { int res; res=_sym_del_export(name,(TDlm*)-1); if (res) _dlm_resolve_to_sym(name); return res; }