home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 August - Disc 3 / chip_20018103_hu.iso / amiga / chiputil / wipeout.lha / source / pools.c < prev    next >
C/C++ Source or Header  |  1998-06-04  |  12KB  |  548 lines

  1. /*
  2.  * $Id: pools.c 1.20 1998/06/04 17:58:10 olsen Exp olsen $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * Wipeout -- Traces and munges memory and detects memory trashing
  7.  *
  8.  * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  9.  * Public Domain
  10.  */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "global.h"
  14. #endif    /* _GLOBAL_H */
  15.  
  16. /******************************************************************************/
  17.  
  18. #include "installpatches.h"
  19.  
  20. /******************************************************************************/
  21.  
  22. STATIC struct MinList PoolList;
  23.  
  24. STATIC struct SignalSemaphore DummySemaphore;
  25.  
  26. /******************************************************************************/
  27.  
  28. VOID
  29. SetupPoolList(VOID)
  30. {
  31.     /* set up the memory pool registry */
  32.     NewList((struct List *)&PoolList);
  33.  
  34.     /* initialize the dummy semaphore */
  35.     InitSemaphore(&DummySemaphore);
  36. }
  37.  
  38. /******************************************************************************/
  39.  
  40. VOID
  41. HoldPoolSemaphore(struct PoolHeader * ph,ULONG pc)
  42. {
  43.     /* hold the pool semaphore for an instant, breaking
  44.      * the Forbid() state
  45.      */
  46.     ObtainSemaphore(&DummySemaphore);
  47.     ReleaseSemaphore(&DummySemaphore);
  48.  
  49.     /* try to gain control over the pool; if this fails,
  50.      * somebody else must be mucking with pool at the
  51.      * moment, which is not such a good idea
  52.      */
  53.     if(CANNOT AttemptSemaphore(&ph->ph_SignalSemaphore))
  54.     {
  55.         ULONG segment;
  56.         ULONG offset;
  57.  
  58.         VoiceComplaint(NULL,NULL,"Two tasks are accessing the same pool at the same time\n");
  59.  
  60.         DPrintf("   Already being used by task 0x%08lx",ph->ph_PoolOwner);
  61.  
  62.         if(GetTaskName(ph->ph_PoolOwner,GlobalNameBuffer,sizeof(GlobalNameBuffer)))
  63.         {
  64.             DPrintf(", %s \"%s\"",GetTaskTypeName(GetTaskType(ph->ph_PoolOwner)),GlobalNameBuffer);
  65.         }
  66.  
  67.         DPrintf("\n");
  68.  
  69.         if(FindAddress(ph->ph_PoolOwnerPC,sizeof(GlobalNameBuffer),GlobalNameBuffer,&segment,&offset))
  70.         {
  71.             DPrintf("                         from \"%s\" Hunk %04lx Offset %08lx\n",GlobalNameBuffer,segment,offset);
  72.         }
  73.  
  74.         DPrintf("Attempting to be used by task 0x%08lx",FindTask(NULL));
  75.  
  76.         if(GetTaskName(NULL,GlobalNameBuffer,sizeof(GlobalNameBuffer)))
  77.         {
  78.             DPrintf(", %s \"%s\"",GetTaskTypeName(GetTaskType(NULL)),GlobalNameBuffer);
  79.         }
  80.  
  81.         DPrintf("\n");
  82.  
  83.         if(FindAddress(NULL,sizeof(GlobalNameBuffer),GlobalNameBuffer,&segment,&offset))
  84.         {
  85.             DPrintf("                      from \"%s\" Hunk %04lx Offset %08lx\n",GlobalNameBuffer,segment,offset);
  86.         }
  87.  
  88.         /* wait for the other guy to release the pool */
  89.         ObtainSemaphore(&ph->ph_SignalSemaphore);
  90.     }
  91.  
  92.     /* register the new owner */
  93.     ph->ph_PoolOwner    = FindTask(NULL);
  94.     ph->ph_PoolOwnerPC    = pc;
  95. }
  96.  
  97. VOID
  98. ReleasePoolSemaphore(struct PoolHeader * ph)
  99. {
  100.     ReleaseSemaphore(&ph->ph_SignalSemaphore);
  101. }
  102.  
  103. /******************************************************************************/
  104.  
  105. BOOL
  106. PuddleIsInPool(struct PoolHeader * ph,APTR mem)
  107. {
  108.     BOOL found = FALSE;
  109.  
  110.     if(IsPuddleListConsistent(ph))
  111.     {
  112.         struct TrackHeader * th;
  113.  
  114.         /* check whether the given allocation went into the
  115.          * given pool
  116.          */
  117.         for(th = (struct TrackHeader *)ph->ph_Puddles.mlh_Head ;
  118.             th->th_MinNode.mln_Succ != NULL ;
  119.             th = (struct TrackHeader *)th->th_MinNode.mln_Succ)
  120.         {
  121.             UBYTE * thatMem;
  122.     
  123.             thatMem = (UBYTE *)(th + 1);
  124.             thatMem += PreWallSize;
  125.     
  126.             if(thatMem == mem)
  127.             {
  128.                 found = TRUE;
  129.                 break;
  130.             }
  131.         }
  132.     }
  133.  
  134.     return(found);
  135. }
  136.  
  137. /******************************************************************************/
  138.  
  139. VOID
  140. RemovePuddle(struct TrackHeader * th)
  141. {
  142.     /* unregister a puddle from a pool */
  143.     Remove((struct Node *)th);
  144.     th->th_Magic = 0;
  145. }
  146.  
  147. VOID
  148. AddPuddle(struct PoolHeader * ph,struct TrackHeader * th)
  149. {
  150.     /* register a puddle in a pool */
  151.     AddTail((struct List *)&ph->ph_Puddles,(struct Node *)th);
  152. }
  153.  
  154. /******************************************************************************/
  155.  
  156. struct PoolHeader *
  157. FindPoolHeader(APTR poolHeader)
  158. {
  159.     struct PoolHeader * result = NULL;
  160.     struct PoolHeader * node;
  161.  
  162.     /* determine the pool header being tracked, if there
  163.      * is one
  164.      */
  165.     for(node = (struct PoolHeader *)PoolList.mlh_Head ;
  166.         node->ph_MinNode.mln_Succ != NULL ;
  167.         node = (struct PoolHeader *)node->ph_MinNode.mln_Succ)
  168.     {
  169.         if(node->ph_PoolHeader == poolHeader)
  170.         {
  171.             result = node;
  172.             break;
  173.         }
  174.     }
  175.  
  176.     return(result);
  177. }
  178.  
  179. /******************************************************************************/
  180.  
  181. BOOL
  182. DeletePoolHeader(ULONG * stackFrame,struct PoolHeader * ph)
  183. {
  184.     struct TrackHeader * th;
  185.     BOOL deleteIt = TRUE;
  186.  
  187.     /* In any event, remove the pool from the public list.
  188.      * It is going to be deleted or let go in a minute.
  189.      */
  190.     Remove((struct Node *)ph);
  191.  
  192.     /* gain exclusive access to the pool */
  193.     HoldPoolSemaphore(ph,stackFrame[16]);
  194.     ReleasePoolSemaphore(ph);
  195.  
  196.     if(IsPuddleListConsistent(ph))
  197.     {
  198.         for(th = (struct TrackHeader *)ph->ph_Puddles.mlh_Head ;
  199.             th->th_MinNode.mln_Succ != NULL ;
  200.             th = (struct TrackHeader *)th->th_MinNode.mln_Succ)
  201.         {
  202.             /* Check whether this pool has dead allocations.
  203.              * If so, do not deallocate it.
  204.              */
  205.             if(th->th_Magic == 0)
  206.             {
  207.                 deleteIt = FALSE;
  208.             }
  209.             else
  210.             {
  211.                 /* Check whether this puddle has been
  212.                  * stomped upon. If so, do not free the
  213.                  * pool.
  214.                  */
  215.                 if(CheckStomping(stackFrame,th))
  216.                 {
  217.                     deleteIt = FALSE;
  218.                 }
  219.  
  220.                 /* Will be dead food in a minute. */
  221.                 th->th_Magic = 0;
  222.             }
  223.         }
  224.  
  225.         /* if we can proceed to deallocate the
  226.          * pool, trash all its allocations
  227.          */
  228.         if(deleteIt)
  229.         {
  230.             struct TrackHeader * node;
  231.             struct TrackHeader * next;
  232.             LONG allocationSize;
  233.  
  234.             for(node = (struct TrackHeader *)ph->ph_Puddles.mlh_Head ;
  235.                (next = (struct TrackHeader *)node->th_MinNode.mln_Succ) != NULL ;
  236.                 node = next)
  237.             {
  238.                 allocationSize = node->th_NameTagLen + sizeof(*node) + PreWallSize + node->th_Size + node->th_PostSize;
  239.                 if(node->th_NameTagLen > 0)
  240.                 {
  241.                     node = (struct TrackHeader *)(((ULONG)node) - node->th_NameTagLen);
  242.                 }
  243.  
  244.                 MungMem((ULONG *)node,allocationSize,DEADBEEF);
  245.             }
  246.         }
  247.     }
  248.  
  249.     if(NOT ph->ph_Consistent)
  250.     {
  251.         deleteIt = FALSE;
  252.     }
  253.  
  254.     if(deleteIt)
  255.     {
  256.         APTR poolHeader;
  257.         ULONG * mem;
  258.         LONG allocationSize;
  259.  
  260.         mem = (ULONG *)(((ULONG)ph) - ph->ph_NameTagLen);
  261.         allocationSize = ph->ph_NameTagLen + sizeof(*ph);
  262.  
  263.         poolHeader = ph->ph_PoolHeader;
  264.  
  265.         MungMem(mem,allocationSize,DEADBEEF);
  266.  
  267.         (*OldDeletePool)(poolHeader,SysBase);
  268.     }
  269.     else
  270.     {
  271.         DumpPoolOwner(ph);
  272.     }
  273.  
  274.     return(deleteIt);
  275. }
  276.  
  277. struct PoolHeader *
  278. CreatePoolHeader(ULONG attributes,ULONG puddleSize,ULONG threshSize,ULONG pc)
  279. {
  280.     struct PoolHeader * result = NULL;
  281.     APTR header;
  282.  
  283.     /* create the pool with the MEMF_CLEAR bit cleared; if there is
  284.      * any clearing to be done, we want to do it on our own
  285.      */
  286.     header = (*OldCreatePool)(attributes & (~MEMF_CLEAR),puddleSize,threshSize,SysBase);
  287.     if(header != NULL)
  288.     {
  289.         struct PoolHeader * ph;
  290.         LONG nameTagLen;
  291.  
  292.         nameTagLen = 0;
  293.  
  294.         /* get the name of the current task, if this is necessary */
  295.         if(NameTag)
  296.         {
  297.             nameTagLen = GetNameTagLen(pc);
  298.         }
  299.     
  300.         ph = (*OldAllocPooled)(header,nameTagLen + sizeof(*ph),SysBase);
  301.         if(ph != NULL)
  302.         {
  303.             /* the allocation above may have broken a Forbid(), so we
  304.              * retry reading the creator information
  305.              */
  306.             if(NameTag)
  307.             {
  308.                 LONG newNameTagLen;
  309.  
  310.                 newNameTagLen = GetNameTagLen(pc);
  311.  
  312.                 /* the data should not be different, but if it is
  313.                  * (unlikely), don't bother to tag this header
  314.                  */
  315.                 if(newNameTagLen != nameTagLen)
  316.                 {
  317.                     nameTagLen = 0;
  318.                 }
  319.             }
  320.  
  321.             /* the name tag header precedes the pool header */
  322.             if(nameTagLen > 0)
  323.             {
  324.                 FillNameTag(ph,nameTagLen);
  325.  
  326.                 /* skip the name tag header */
  327.                 ph = (struct PoolHeader *)(((ULONG)ph) + nameTagLen);
  328.             }
  329.  
  330.             /* fill in the usual header data */
  331.             ph->ph_PoolHeader    = header;
  332.             ph->ph_PC            = pc;
  333.             ph->ph_Owner        = FindTask(NULL);
  334.             ph->ph_OwnerType    = GetTaskType(NULL);
  335.             ph->ph_NameTagLen    = nameTagLen;
  336.             ph->ph_Consistent    = TRUE;
  337.  
  338.             GetSysTime(&ph->ph_Time);
  339.     
  340.             ph->ph_Attributes = attributes;
  341.             NewList((struct List *)&ph->ph_Puddles);
  342.     
  343.             memset(&ph->ph_SignalSemaphore,0,sizeof(ph->ph_SignalSemaphore));
  344.             InitSemaphore(&ph->ph_SignalSemaphore);
  345.             ph->ph_PoolOwner = NULL;
  346.  
  347.             AddTail((struct List *)&PoolList,(struct Node *)ph);
  348.  
  349.             result = ph;
  350.         }
  351.         else
  352.         {
  353.             (*OldDeletePool)(header,SysBase);
  354.         }
  355.     }
  356.  
  357.     return(result);
  358. }
  359.  
  360. /******************************************************************************/
  361.  
  362. VOID
  363. CheckPools(VOID)
  364. {
  365.     struct PoolHeader * ph;
  366.     struct TrackHeader * th;
  367.     ULONG totalBytes;
  368.     ULONG totalAllocations;
  369.     ULONG totalPools;
  370.     BOOL poolOwnerDumped;
  371.  
  372.     totalBytes = 0;
  373.     totalAllocations = 0;
  374.     totalPools = 0;
  375.  
  376.     Forbid();
  377.  
  378.     /* check all registered pools */
  379.     for(ph = (struct PoolHeader *)PoolList.mlh_Head ;
  380.         ph->ph_MinNode.mln_Succ != NULL ;
  381.         ph = (struct PoolHeader *)ph->ph_MinNode.mln_Succ)
  382.     {
  383.         poolOwnerDumped = FALSE;
  384.  
  385.         if(IsPuddleListConsistent(ph))
  386.         {
  387.             /* check all allocations in this pool */
  388.             for(th = (struct TrackHeader *)ph->ph_Puddles.mlh_Head ;
  389.                 th->th_MinNode.mln_Succ != NULL ;
  390.                 th = (struct TrackHeader *)th->th_MinNode.mln_Succ)
  391.             {
  392.                 /* Check whether the header data is consistent. */
  393.                 if(IsValidTrackHeader(th) && IsTrackHeaderChecksumCorrect(th))
  394.                 {
  395.                     /* Don't count dead allocations. */
  396.                     if(th->th_Magic != 0)
  397.                     {
  398.                         /* check if the allocation was trashed */
  399.                         if(CheckStomping(NULL,th))
  400.                         {
  401.                             /* if the allocation was trashed,
  402.                              * show the pool it belongs to
  403.                              */
  404.                             if(NOT poolOwnerDumped)
  405.                             {
  406.                                 DumpPoolOwner(ph);
  407.         
  408.                                 poolOwnerDumped = TRUE;
  409.                             }
  410.                         }
  411.         
  412.                         totalBytes += th->th_Size;
  413.                         totalAllocations++;
  414.                     }
  415.                 }
  416.             }
  417.         }
  418.  
  419.         /* check whether the creator of this pool
  420.          * is still with us
  421.          */
  422.         if(NOT IsTaskStillAround(ph->ph_Owner))
  423.         {
  424.             VoiceComplaint(NULL,NULL,"Orphaned pool?\n");
  425.             DumpPoolOwner(ph);
  426.         }
  427.  
  428.         totalPools++;
  429.     }
  430.  
  431.     Permit();
  432.  
  433.     DPrintf("%ld byte(s) in %ld allocation(s) in %ld pool(s).\n",totalBytes,totalAllocations,totalPools);
  434. }
  435.  
  436. /******************************************************************************/
  437.  
  438. VOID
  439. ShowUnmarkedPools(VOID)
  440. {
  441.     struct PoolHeader * ph;
  442.     struct TrackHeader * th;
  443.     ULONG totalBytes;
  444.     ULONG totalAllocations;
  445.     ULONG totalPools;
  446.  
  447.     /* Show and count all pooled memory allocations. */
  448.  
  449.     totalBytes = 0;
  450.     totalAllocations = 0;
  451.     totalPools = 0;
  452.  
  453.     Forbid();
  454.  
  455.     /* check all registered pools */
  456.     for(ph = (struct PoolHeader *)PoolList.mlh_Head ;
  457.         ph->ph_MinNode.mln_Succ != NULL ;
  458.         ph = (struct PoolHeader *)ph->ph_MinNode.mln_Succ)
  459.     {
  460.         if(IsPuddleListConsistent(ph))
  461.         {
  462.             /* check all allocations in this pool */
  463.             for(th = (struct TrackHeader *)ph->ph_Puddles.mlh_Head ;
  464.                 th->th_MinNode.mln_Succ != NULL ;
  465.                 th = (struct TrackHeader *)th->th_MinNode.mln_Succ)
  466.             {
  467.                 /* Don't count dead allocations. */
  468.                 if(th->th_Magic != 0)
  469.                 {
  470.                     if(NOT th->th_Marked)
  471.                     {
  472.                         VoiceComplaint(NULL,th,NULL);
  473.                     }
  474.     
  475.                     totalBytes += th->th_Size;
  476.                     totalAllocations++;
  477.                 }
  478.             }
  479.         }
  480.  
  481.         totalPools++;
  482.     }
  483.  
  484.     Permit();
  485.  
  486.     DPrintf("%ld byte(s) in %ld allocation(s) in %ld pool(s).\n",totalBytes,totalAllocations,totalPools);
  487. }
  488.  
  489. /******************************************************************************/
  490.  
  491. VOID
  492. ChangePuddleMarks(BOOL markSet)
  493. {
  494.     struct PoolHeader * ph;
  495.     struct TrackHeader * th;
  496.  
  497.     /* Mark or unmark all memory puddles. */
  498.  
  499.     Forbid();
  500.  
  501.     for(ph = (struct PoolHeader *)PoolList.mlh_Head ;
  502.         ph->ph_MinNode.mln_Succ != NULL ;
  503.         ph = (struct PoolHeader *)ph->ph_MinNode.mln_Succ)
  504.     {
  505.         if(IsPuddleListConsistent(ph))
  506.         {
  507.             for(th = (struct TrackHeader *)ph->ph_Puddles.mlh_Head ;
  508.                 th->th_MinNode.mln_Succ != NULL ;
  509.                 th = (struct TrackHeader *)th->th_MinNode.mln_Succ)
  510.             {
  511.                 /* Ignore dead allocations. */
  512.                 if(th->th_Magic != 0)
  513.                 {
  514.                     th->th_Marked = markSet;
  515.     
  516.                     /* Repair the checksum value. */
  517.                     FixTrackHeaderChecksum(th);
  518.                 }
  519.             }
  520.         }
  521.     }
  522.  
  523.     Permit();
  524. }
  525.  
  526. /******************************************************************************/
  527.  
  528. BOOL
  529. IsPuddleListConsistent(struct PoolHeader * ph)
  530. {
  531.     BOOL isConsistent = TRUE;
  532.  
  533.     Forbid();
  534.  
  535.     if(NOT IsMemoryListConsistent(&ph->ph_Puddles))
  536.     {
  537.         ph->ph_Consistent = FALSE;
  538.  
  539.         isConsistent = FALSE;
  540.  
  541.         NewList((struct List *)&ph->ph_Puddles);
  542.     }
  543.  
  544.     Permit();
  545.  
  546.     return(isConsistent);
  547. }
  548.