by Michael Sinz (MKSoft Development) Copyright 1992-2001 - All Rights Reserved SegTracker.c |
by Michael Sinz MKSoft Development Copyright 1992-2001 All Rights Reserved Documentation Enforcer Archive Source code for the main Enforcer tool: Source code for the MMU tool: Source code for SegTracker: Source code for FindHit: Source code for RebootOff: Source code for Move4K: Source code for LawBreaker: | /* * Enforcer by * Michael Sinz * * Copyright 1992-2001 * All Rights Reserved * ***************************************************************************** * * * Permission is hereby granted to distribute the Enforcer archive * * containing the executables and documentation for non-commercial purposes * * so long as the archive and its contents are not modified in any way. * * * * Enforcer and related tools are not in the public domain. * * * * Enforcer and related tools may not be distributed for a profit. * * * ***************************************************************************** * */ /* ******* SegTracker ************************************************************ * * NAME * SegTracker - A global SegList tracking utility * * SYNOPSIS * A global tracking utility for disk loaded files including * libraries and devices. If placed in the startup-sequence * right after SetPatch, it will track all disk loaded segments * (other than those loaded by SetPatch) * * FUNCTION * SegTracker will patch the DOS LoadSeg(), NewLoadSeg(), and UnLoadSeg() * functions in order to track the SegLists that are loaded. * SegTracker keeps these seglist stored in a "safe" manner and * even handles programs which SegList split. * * The first time the program is run, it installs the patches * and semaphore. After that point, it just finds the semaphore * and uses it. * * When SegTracker is installed, it will scan the ROM for ROM modules * and add their locations to the tracking list such that addresses * within those modules can be identified. Note that the offsets * from the module is based on the location of the module's ROMTAG. * The NOROM option will prevent this feature from being installed. * * By using SegTracker, it will be possible to better identify * where Enforcer hits come from when dealing with libraries * and devices. Basically, it is a system-global Hunk-o-matic. * * External programs can then pass in an address to SegTracker * either via the command line or via the given function pointer * in the SegTracker semaphore and get back results as to what * hunk and offset the address is at. * * To work with the function directly, you need to find the * the semaphore of "SegTracker" using FindSemaphore(). * The structure found will be the following: * * struct SegSem * { * struct SignalSemaphore seg_Semaphore; * SegTrack *seg_Find; * }; * * The function pointer points to a routine that takes an address * and two pointers to long words for returning the Segment number * and Offset within the segment. The function returns the name * of the file loaded. Note that you must call this function * while in Forbid() and then copy the name as the seglist may * be UnLoadSeg'ed at any moment and the name string will then * no longer be in memory. * * typedef char (* __asm SegTrack(register __a0 ULONG Address, * register __a1 ULONG *SegNum, * register __a2 ULONG *Offset)); * * The above is for use in C code function pointer prototype * in SAS/C 5 and 6. * * INPUTS * SHOW/S - Shows all of the segments being tracked. * * DUMP/S - Displays all of the segment elements being tracked. * * NOROM/S - Tells segtracker not to scan ROM when it is * installed, thus not adding ROM addresses to the * tracking list. * * FIND/M - Find the hex (in $xxxxx format) address in * the tracked segments. Multiple addresses * can be given. * * Options are not available from Workbench as they require * the CLI. However, you can run SegTracker from Workbench * to install it. * * EXAMPLE USAGE * \* * * A simple program that will "find" given addresses in the SegLists * * This program has been compiled with SAS/C 6.2 without errors or * * warnings. * * * * Compiler options: * * DATA=FARONLY PARAMETERS=REGISTER NOSTACKCHECK * * NOMULTIPLEINCLUDES STRINGMERGE STRUCTUREEQUIVALENCE * * MULTIPLECHARACTERCONSTANTS DEBUG=LINE NOVERSION * * OPTIMIZE OPTIMIZERINLOCAL NOICONS * * * * Linker options: * * FindSeg.o TO FindSeg SMALLCODE SMALLDATA NODEBUG LIB LIB:sc.lib * *\ * #include <exec/types.h> * #include <exec/execbase.h> * #include <exec/libraries.h> * #include <exec/semaphores.h> * #include <dos/dos.h> * #include <dos/dosextens.h> * #include <dos/rdargs.h> * * #include <clib/exec_protos.h> * #include <pragmas/exec_sysbase_pragmas.h> * * #include <clib/dos_protos.h> * #include <pragmas/dos_pragmas.h> * * #include <string.h> * * #include "FindSeg_rev.h" * * #define EXECBASE (*(struct ExecBase **)4) * * typedef char (* __asm SegTrack(register __a0 ULONG, * register __a1 ULONG *, * register __a2 ULONG *)); * * struct SegSem * { * struct SignalSemaphore seg_Semaphore; * SegTrack *seg_Find; * }; * * #define SEG_SEM "SegTracker" * * #define TEMPLATE "FIND/M" VERSTAG * * #define OPT_FIND 0 * #define OPT_COUNT 1 * * ULONG cmd(void) * { * struct ExecBase *SysBase; * struct Library *DOSBase; * struct RDArgs *rdargs; * ULONG rc=RETURN_FAIL; * struct SegSem *segSem; * char **hex; * LONG opts[OPT_COUNT]; * * SysBase = EXECBASE; * if (DOSBase = OpenLibrary("dos.library",37)) * { * memset((char *)opts, 0, sizeof(opts)); * * if (!(rdargs = ReadArgs(TEMPLATE, opts, NULL))) * { * PrintFault(IoErr(),NULL); * } * else if (CheckSignal(SIGBREAKF_CTRL_C)) * { * PrintFault(ERROR_BREAK,NULL); * } * else if (segSem=(struct SegSem *)FindSemaphore(SEG_SEM)) * { * rc=RETURN_OK; * if (opts[OPT_FIND]) * { * for (hex=(char **)opts[OPT_FIND];(*hex);hex++) * { * char *p; * ULONG val; * ULONG tmp[4]; * ULONG c; * * val=0; * p=*hex; * if (*p=='$') p++; \* Support $hex *\ * while (*p) * { * c=(ULONG)*p; * if ((c>='a') && (c<='f')) c-=32; * c-='0'; * if (c>9) * { * c-=7; * if (c<10) c=16; * } * * if (c<16) * { * val=(val << 4) + c; * p++; * } * else * { * val=0; * p=&p[strlen(p)]; * } * } * * \* * * Ok, we need to do this within Forbid() * * as segments can unload at ANY time, including * * during AllocMem(), so we use a stack buffer... * * * *\ * Forbid(); * if (p=(*segSem->seg_Find)(tmp[0]=val,&tmp[2],&tmp[3])) * { * char Buffer[200]; * * stccpy(Buffer,p,200); * tmp[1]=(ULONG)Buffer; * VPrintf("$%08lx - %s : Hunk %ld, Offset $%08lx",tmp); * * \* * * Now get the SegList address by passing the * * same pointer for both hunk & offset. Note * * that this is only in the newer SegTrackers * * To test if this worked, check if the result * * of this call is either a hunk or an offset. * *\ * (*segSem->seg_Find)(val,&tmp[0],&tmp[0]); * \* * * This "kludge" is for compatibility reasons * * Check if result is the same as either the hunk * * or the offset. If so, do not print it... * *\ * if ((tmp[0]!=tmp[2]) && (tmp[0]!=tmp[3])) * { * VPrintf(", SegList $%08lx",tmp); * } * * PutStr("\n"); * } * else VPrintf("$%08lx - Not found\n",tmp); * Permit(); * } * } * } * else PutStr("Could not find SegTracker semaphore.\n"); * * if (rdargs) FreeArgs(rdargs); * CloseLibrary(DOSBase); * } * else if (DOSBase=OpenLibrary("dos.library",0)) * { * Write(Output(),"Requires Kickstart 2.04 (37.175) or later.\n",43); * CloseLibrary(DOSBase); * } * * return(rc); * } * * NOTES * The earlier this command is run, the better off it will be in * tracking disk loaded segments. Under debug usage, you may * wish to run the command right *AFTER* SetPatch. * * Some things may not call UnLoadSeg() to free their seglists. * There is no way SegTracker can follow a seglist that is not * unloaded via the dos.library call to UnLoadSeg(). For this * reason, SegTracker adds new LoadSeg() segments to the top * of its list. This way, if any old segments are still on * the list but have been unloaded via some other method * they will not clash with newer segments during the find operation. * * Note that the resident list is one such place where * UnLoadSeg() is not called to free the seglist. Thus, * if something is made resident and then later unloaded * it will still be listed as tracked by SegTracker. * * In order to support a new feature in CPR, the SegTracker function * got a "kludge" added to it. If a segment is found, you can then * call the function again with the same address but with having * both pointers point to the same longword of storage. By doing * this, the function will now return (in that longword) the * SegList pointer (CPTR not BPTR) of the file that contains * the address. The reason this method was used was so it * would be compatible with older SegTracker versions. In older * versions you would not get the result you wanted but you would * also not crash. See the example above for more details on how * to use this feature. The SegTracker FIND option has been * expanded to include this information. * * Due to the fact that I am working on a design of a new set of * debugging tools (Enforcer/SegTracker/etc) I do not wish to * expand the current SegTracker model in too many ways. * * SEE ALSO * "Programming is like sex - * one mistake and you have to support it for life." - Michael Sinz * * BUGS * ******************************************************************************* */ #include <exec/types.h> #include <exec/execbase.h> #include <exec/tasks.h> #include <exec/memory.h> #include <exec/alerts.h> #include <exec/ports.h> #include <exec/libraries.h> #include <exec/semaphores.h> #include <exec/resident.h> #include <dos/dos.h> #include <dos/dosextens.h> #include <dos/rdargs.h> #include <devices/timer.h> #include <workbench/startup.h> #include <workbench/workbench.h> #include <libraries/configvars.h> #include <clib/exec_protos.h> #include <pragmas/exec_pragmas.h> #include <clib/dos_protos.h> #include <pragmas/dos_pragmas.h> #include <string.h> #include "SegTracker_rev.h" #define EXECBASE (*(struct ExecBase **)4) /******************************************************************************/ #define TEMPLATE "SHOW/S,DUMP/S,NOROM/S,FIND/M" VERSTAG #define SEG_SEM "SegTracker" #define OPT_SHOW 0 #define OPT_DUMP 1 #define OPT_NOROM 2 #define OPT_FIND 3 #define OPT_COUNT 4 #define NEWLIST(l) {((struct MinList *)l)->mlh_Head = (struct MinNode *)&(((struct MinList *)l)->mlh_Tail);\ ((struct MinList *)l)->mlh_Tail = NULL;\ ((struct MinList *)l)->mlh_TailPred = (struct MinNode *)l;} typedef char (* __asm SegTrack(register __a0 ULONG,register __a1 ULONG *,register __a2 ULONG *)); struct SegSem { struct SignalSemaphore seg_Semaphore; SegTrack *seg_Find; struct MinList seg_List; }; struct SegArray { ULONG seg_Address; ULONG seg_Size; }; struct SegNode { struct MinNode seg_Node; char *seg_Name; struct SegArray seg_Array[1]; }; /* * Some global data needed to make this all work... */ struct ExecBase *SysBase; struct Library *DOSBase; struct SegSem MySem; extern long LVOLoadSeg; extern long LVONewLoadSeg; extern long LVOUnLoadSeg; // extern long LVORemSegment; extern long __stdargs MyLoadSeg(); extern long __stdargs MyNewLoadSeg(); extern long __stdargs MyUnLoadSeg(); // extern long __stdargs MyRemSegment(); extern ULONG OldLoadSeg; extern ULONG OldNewLoadSeg; extern ULONG OldUnLoadSeg; // extern ULONG OldRemSegment; char * __asm FindSeg(register __a0 ULONG Address,register __a1 ULONG *SegNum,register __a2 ULONG *Offset); VOID AddROM(VOID); ULONG cmd(void) { struct Process *proc; struct RDArgs *rdargs=NULL; struct WBStartup *msg=NULL; ULONG rc=RETURN_FAIL; struct SegSem *segSem=NULL; char **hex; LONG opts[OPT_COUNT]; SysBase = EXECBASE; NEWLIST(&(MySem.seg_List)); proc=(struct Process *)FindTask(NULL); if (!(proc->pr_CLI)) { WaitPort(&(proc->pr_MsgPort)); msg=(struct WBStartup *)GetMsg(&(proc->pr_MsgPort)); } if (DOSBase = OpenLibrary("dos.library",37)) { memset((char *)opts, 0, sizeof(opts)); /* * Do the option parsing * If from Workbench, no options... * If from CLI, use ReadArgs */ if (msg) rc=RETURN_OK; else { /* * Started from CLI so do standard ReadArgs */ if (!(rdargs = ReadArgs(TEMPLATE, opts, NULL))) PrintFault(IoErr(),NULL); else if (CheckSignal(SIGBREAKF_CTRL_C)) PrintFault(ERROR_BREAK,NULL); else rc=RETURN_OK; } if (RETURN_OK==rc) { Forbid(); if (!(segSem=(struct SegSem *)FindSemaphore(SEG_SEM))) { InitSemaphore((struct SignalSemaphore *)&MySem); segSem=&MySem; segSem->seg_Semaphore.ss_Link.ln_Name=SEG_SEM; segSem->seg_Semaphore.ss_Link.ln_Pri=-127; segSem->seg_Find=FindSeg; AddSemaphore((struct SignalSemaphore *)segSem); /* Add the ROM modules (unless told not to)... */ if (!opts[OPT_NOROM]) AddROM(); } if (opts[OPT_SHOW]) { struct SegNode *seg; PutStr("Segments being tracked:\n"); seg=(struct SegNode *)segSem->seg_List.mlh_Head; while ((seg->seg_Node.mln_Succ) && (!(SetSignal(0,0) & SIGBREAKF_CTRL_C))) { PutStr("\t"); PutStr(seg->seg_Name); PutStr("\n"); seg=(struct SegNode *)(seg->seg_Node.mln_Succ); } } if (opts[OPT_DUMP]) { struct SegNode *seg; ULONG tmp[3]; PutStr("Segments being tracked:\n"); seg=(struct SegNode *)segSem->seg_List.mlh_Head; while ((seg->seg_Node.mln_Succ) && (!(SetSignal(0,0) & SIGBREAKF_CTRL_C))) { tmp[0]=(ULONG)seg->seg_Name; VPrintf("\nModule '%s'\n",(LONG *)tmp); tmp[0]=0; while (tmp[1]=seg->seg_Array[tmp[0]].seg_Address) { tmp[2]=seg->seg_Array[tmp[0]].seg_Size; VPrintf("\tHunk%3ld @ $%08lx Size $%08lx\n",(LONG *)tmp); tmp[0]++; } seg=(struct SegNode *)(seg->seg_Node.mln_Succ); } } if (opts[OPT_FIND]) for (hex=(char **)opts[OPT_FIND];(*hex);hex++) { char *p; ULONG val; ULONG tmp[4]; ULONG c; val=0; p=*hex; if (*p=='$') p++; /* Support $hex */ while (*p) { c=(ULONG)*p; if ((c>='a') && (c<='f')) c-=32; c-='0'; if (c>9) { c-=7; if (c<10) c=16; } if (c<16) { val=(val << 4) + c; p++; } else { val=0; p=&p[strlen(p)]; } } if (p=(*segSem->seg_Find)(tmp[0]=val,&tmp[2],&tmp[3])) { char Buffer[200]; c=0; while (c<200) if (!(Buffer[c++]=*p++)) c=200; tmp[1]=(ULONG)Buffer; VPrintf("$%08lx - %s : Hunk %ld, Offset $%08lx",(LONG *)tmp); (*segSem->seg_Find)(val,&tmp[0],&tmp[0]); if ((tmp[0]!=tmp[2]) && (tmp[0]!=tmp[3])) { VPrintf(", SegList $%08lx",(LONG *)tmp); } PutStr("\n"); } else VPrintf("$%08lx - Not found\n",(LONG *)tmp); } Permit(); if (CheckSignal(SIGBREAKF_CTRL_C)) PrintFault(ERROR_BREAK,NULL); } if (rdargs) FreeArgs(rdargs); /* * If we are the running version, install patches here... * ...and disconnnect from the CLI... */ if (segSem == &MySem) { /* Install the SetFunction here */ Forbid(); OldLoadSeg =(ULONG)SetFunction(DOSBase,(long)&LVOLoadSeg,(unsigned long (*)())MyLoadSeg); OldNewLoadSeg=(ULONG)SetFunction(DOSBase,(long)&LVONewLoadSeg,(unsigned long (*)())MyNewLoadSeg); OldUnLoadSeg =(ULONG)SetFunction(DOSBase,(long)&LVOUnLoadSeg,(unsigned long (*)())MyUnLoadSeg); // OldRemSegment=(ULONG)SetFunction(DOSBase,(long)&LVORemSegment,(unsigned long (*)())MyRemSegment); Permit(); /* * Now disconnect... * WB: means clear the msg->sm_Segment BPTR... * CLI: means clear the CLI->Module BPTR... */ if (msg) msg->sm_Segment=NULL; else ((struct CommandLineInterface *)BADDR(((struct Process *)FindTask(NULL))->pr_CLI))->cli_Module=NULL; } CloseLibrary(DOSBase); } else { if (!msg) if (DOSBase=OpenLibrary("dos.library",0)) { Write(Output(),"Requires Kickstart 2.04 (37.175) or later.\n",43); CloseLibrary(DOSBase); } } if (msg) { Forbid(); ReplyMsg((struct Message *)msg); } return(0); } /* * Track the loaded segment... This will add a SegNode to * the semaphore for later work... */ VOID __asm TrackSeg(register __d0 BPTR seg,register __a0 char *Name) { struct SegNode *node; ULONG *p; ULONG count; /* Track the segment... */ if ((seg) && (Name)) { count=sizeof(struct SegArray); p=BADDR(seg); while (*p) { count+=sizeof(struct SegArray); p=BADDR(*p); } if (node=AllocVec(sizeof(struct SegNode)+count+1+strlen(Name),MEMF_PUBLIC|MEMF_CLEAR)) { node->seg_Name=(char *)(((ULONG)node)+sizeof(struct SegNode)+count); strcpy(node->seg_Name,Name); count=0; p=(ULONG *)seg; while (p=BADDR(p)) { node->seg_Array[count].seg_Address=(ULONG)p; node->seg_Array[count].seg_Size=p[-1]-4; p=(ULONG *)p[0]; count++; } Forbid(); AddHead((struct List *)&MySem.seg_List,(struct Node *)node); Permit(); } } } /* * Untrack the segment that is about to be * unloaded. Note that it handles partial unload * by looking for individual segments and * only when all of them have been removed * will it removed the tracking node. */ VOID __asm UnTrackSeg(register __d1 BPTR seg) { ULONG *p; ULONG flag; struct SegArray *array; struct SegNode *node; struct SegNode *tmp; p=(ULONG *)seg; while (p=BADDR(p)) { Forbid(); node=(struct SegNode *)MySem.seg_List.mlh_Head; while (node->seg_Node.mln_Succ) { flag=0; array=node->seg_Array; while (array->seg_Address) { if (array->seg_Address==(ULONG)p) array->seg_Size=0; flag |= array->seg_Size; array++; } tmp=(struct SegNode *)node->seg_Node.mln_Succ; if (!flag) { /* Segment all gone... */ Remove((struct Node *)node); FreeVec(node); } node=tmp; } Permit(); p=(ULONG *)p[0]; } } /* * Find the segment that this address is connected to... */ char * __asm FindSeg(register __a0 ULONG Address,register __a1 ULONG *SegNum,register __a2 ULONG *Offset) { struct SegNode *node; char *Name=NULL; ULONG count; node=(struct SegNode *)MySem.seg_List.mlh_Head; while ((node->seg_Node.mln_Succ) && (!Name)) { count=0; while (node->seg_Array[count].seg_Address) { if ((Address > node->seg_Array[count].seg_Address) && (Address < (node->seg_Array[count].seg_Address+node->seg_Array[count].seg_Size))) { *SegNum=count; *Offset=Address-node->seg_Array[count].seg_Address-4; Name=node->seg_Name; /* * Kludge feature: If the SegNum and Offset * point to the same longword, return the * SegList pointer insted of the hunk/offset * pair. This is for CPR in SAS/C++ 6.50 */ if (SegNum==Offset) *SegNum=node->seg_Array[0].seg_Address; } count++; } node=(struct SegNode *)node->seg_Node.mln_Succ; } return(Name); } /* * Add the ROM modules to the tracking list... * * What we will do is search the ROM for ROMTAGs and * add them to the list as found... */ VOID AddROM(VOID) { struct SegNode *last=0; UWORD *ROM; ULONG index; /* Ok, lets find the ROM start address... */ ROM=(UWORD *)(0xFFF80000 & ((ULONG)(EXECBASE->LibNode.lib_Node.ln_Name))); /* Ok, no start the search... */ for (index=0;index<(512*1024/2);index++) { if (ROM[index]==RTC_MATCHWORD) { struct Resident *romTag=(struct Resident *)(&ROM[index]); if (romTag==romTag->rt_MatchTag) { char *from; index=(((ULONG)(romTag->rt_EndSkip))-((ULONG)ROM))/2-1; from=romTag->rt_IdString; /* * This simple check makes sure that there * is a version/date on the module. If not, * it is assumed to be a "special" one. */ while ((*from) && (*from!='(')) from++; if (*from) { char *new; from=romTag->rt_IdString; if (last) last->seg_Array[0].seg_Size=((ULONG)romTag)-last->seg_Array[0].seg_Address; last=AllocVec(sizeof(struct SegNode)+sizeof(struct SegArray)+strlen(from)+1+6,MEMF_CLEAR|MEMF_PUBLIC); if (last) { last->seg_Array[0].seg_Address=(ULONG)romTag; last->seg_Name=(char *)&(last->seg_Array[2]); new=last->seg_Name; strcpy(new,"ROM - "); while (*new) new++; while (*from) { if (*from>=' ') *new++=*from; from++; } /* Add to the list... */ AddTail((struct List *)&MySem.seg_List,(struct Node *)last); } } } } } if (last) last->seg_Array[0].seg_Size=((ULONG)(&ROM[index]))-last->seg_Array[0].seg_Address; } | ||