⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stackwalker.cpp

📁 奇迹世界公用文件源代码,研究网络游戏的朋友可以研究下
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//  if open failed, redirect output to stdout
static void AllocCheckFileOpen(BOOL bAppend = true) {
  // is the File already open? If not open it...
  if (g_fFile == NULL)
    if (g_pszAllocLogName != NULL)
    {
      if (bAppend == false)
        g_fFile = _tfopen(g_pszAllocLogName, _T("w"));
      else
        g_fFile = _tfopen(g_pszAllocLogName, _T("a"));
    }
  if (g_fFile == NULL)
    g_fFile = stdout;
}

// Write Date/Time to specified file (will also work after 2038)
static void WriteDateTime(FILE *fFile, BOOL asXMLAttrs = FALSE) {
  TCHAR pszTemp[11], pszTemp2[11];

  if (fFile != NULL) {
    _tstrdate( pszTemp );
    _tstrtime( pszTemp2 );
    if (asXMLAttrs == FALSE)
      _ftprintf(fFile,  _T("%s %s"), pszTemp, pszTemp2 );  // also ok after year 2038 (asctime is NOT ok)
    else
      _ftprintf(fFile,  _T("date=\"%s\" time=\"%s\" "), pszTemp, pszTemp2 );  // also ok after year 2038 (asctime is NOT ok)
  }
}  // WriteDateTime


/*******************************************************************************
 * Hash-Tabelle
 *******************************************************************************/
// Memory for the EIP-Address (is used by the ShowStack-method)
#define MAX_EIP_LEN_BUF 4

#define ALLOC_ENTRY_NOT_FOUND 0xFFFFFFFF

typedef struct AllocHashEntryType {
  long                       lRequestID;    // RequestID from CRT (if 0, then this entry is empty)
  size_t                     nDataSize;     // Size of the allocated memory
  char                       cRemovedFlag;  // 0 => memory was not yet released
  struct AllocHashEntryType  *Next;
  // Callstack for EIP
  DWORD                      dwEIPOffset;
  DWORD                      dwEIPLen;
  char                       pcEIPAddr[MAX_EIP_LEN_BUF];
  // Callstack for ESP
  DWORD                      dwESPOffset;
  DWORD                      dwESPLen;
  char                       pcESPAddr[MAX_ESP_LEN_BUF];
} AllocHashEntryType;

static AllocHashEntryType AllocHashTable[ALLOC_HASH_ENTRIES];
static ULONG AllocHashEntries = 0;
static ULONG AllocHashCollisions = 0;
static ULONG AllocHashFreed = 0;
static ULONG AllocHashMaxUsed = 0; // maximal number of concurrent entries
static ULONG AllocHashCurrentCount = 0;

static ULONG AllocHashMaxCollisions = 0;
static ULONG AllocHashCurrentCollisions = 0;

// ##########################################################################################
#ifdef WITH_IMALLOC_SPY
// eigene Tabelle f? die IMallocs:
typedef struct IMallocHashEntryType {
  void                       *pData;    // Key-Word
  size_t                     nDataSize;     // gr鲞e des Datenblocks (optional)
  char                       cRemovedFlag;  // 0 => nicht wurde noch nicht freigegeben
  struct IMallocHashEntryType  *Next;
  // Callstack f? EIP
  DWORD                      dwEIPOffset;
  DWORD                      dwEIPLen;
  char                       pcEIPAddr[MAX_EIP_LEN_BUF];
  // Callstack f? ESP
  DWORD                      dwESPOffset;
  DWORD                      dwESPLen;
  char                       pcESPAddr[MAX_ESP_LEN_BUF];
} IMallocHashEntryType;

static IMallocHashEntryType IMallocHashTable[ALLOC_HASH_ENTRIES];

static ULONG IMallocHashEntries = 0;
static ULONG IMallocHashCollisions = 0;
static ULONG IMallocHashFreed = 0;
static ULONG IMallocHashMaxUsed = 0; // maximal number of concurrent entries
static ULONG IMallocHashCurrentCount = 0;

static ULONG IMallocHashMaxCollisions = 0;
static ULONG IMallocHashCurrentCollisions = 0;


//static void AllocHashOut(FILE*);
static ULONG IMallocHashOutLeaks(FILE*);

// AllocHashFunction
//   Die eigentliche Hash-Funktion (hier ganz simpel)
static ULONG IMallocHashFunction(void *pData) {
  ULONG ulTemp;
  DWORD dwPointer = (DWORD) pData;

  // relativ simpler Mechanismus f? die Hash-Funktion,
  // mir ist nur nix besseres eingefallen...
  ulTemp = dwPointer % ALLOC_HASH_ENTRIES;

  _ASSERTE( (ulTemp >= 0) && (ulTemp < ALLOC_HASH_ENTRIES) );

  return ulTemp;
}  // AllocHashFunction

// IMallocHashInsert
//   pData: Key-Word (Pointer to address)
//   pContext:   Context-Record, for retrieving Callstack (EIP and EBP is only needed)
//   nDataSize:  How many bytes
void IMallocHashInsert(void *pData, CONTEXT &Context, size_t nDataSize) {
  ULONG HashIdx;
  IMallocHashEntryType *pHashEntry;

  // ermittle Statistische Werte
  IMallocHashEntries++;
  IMallocHashCurrentCount++;
  if (IMallocHashCurrentCount > IMallocHashMaxUsed)
    IMallocHashMaxUsed = IMallocHashCurrentCount;

  // ermittle den Hash-Wert
  HashIdx = IMallocHashFunction(pData);

  // Eintrag darf nicht gr鲞er als die Hash-Tabelle sein
  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);

  pHashEntry = &IMallocHashTable[HashIdx];
  if (pHashEntry->pData == 0) {
    // es ist noch kein Eintrag da
  }
  else {
    //Statistische Daten:
    IMallocHashCollisions++;
    IMallocHashCurrentCollisions++;
    if (IMallocHashCurrentCollisions > IMallocHashMaxCollisions)
      IMallocHashMaxCollisions = IMallocHashCurrentCollisions;

    // Eintrag ist schon belegt, verkette die Eintr?e
    // wenn dies oft vorkommt, sollte man entweder die Tabelle vergr鲞ern oder eine
    // andere Hash-Funktion w?len
    while(pHashEntry->Next != NULL) {
      pHashEntry = pHashEntry->Next;
    }

    pHashEntry->Next = (IMallocHashEntryType*) _calloc_dbg(sizeof(IMallocHashEntryType), 1, _CRT_BLOCK, __FILE__, __LINE__);
    pHashEntry = pHashEntry->Next;

  }
  pHashEntry->pData = pData;  // Key-Word
  pHashEntry->nDataSize = nDataSize;
  pHashEntry->Next = NULL;
  // Get EIP and save it in the record
  pHashEntry->dwEIPOffset = Context.Eip;
  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr), MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {
    // Could not read memory... remove everything...
    memset(pHashEntry->pcEIPAddr, 0, MAX_EIP_LEN_BUF);
    pHashEntry->dwEIPLen = 0;
    pHashEntry->dwEIPOffset = 0;
  }

  // Get ESP and save it in the record
  pHashEntry->dwESPOffset = Context.Ebp;
  if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {
    // Could not read memory... remove everything...
    memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
    pHashEntry->dwESPLen = 0;
    pHashEntry->dwESPOffset = 0;

    // Check if I tried to read too much...
    if (GetLastError() == ERROR_PARTIAL_COPY)
    {
      // ask how many I can read:
      MEMORY_BASIC_INFORMATION MemBuffer;
      DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer, sizeof(MemBuffer));
      if (dwRet > 0)
      {
        // calculate the length
        DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;
        if ( (len > 0) && (len < MAX_ESP_LEN_BUF) )
        {
          // try to read it again (with the shorter length)
          if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)
          {
            // ok, now everything goes wrong... remove it...
            memset(pHashEntry->pcESPAddr, 0, MAX_ESP_LEN_BUF);
            pHashEntry->dwESPLen = 0;
            pHashEntry->dwESPOffset = 0;
          }
          else
          {
            pHashEntry->dwESPOffset = Context.Ebp;
          }
        }
      } // VirtualQuery was successfully
    }  // ERROR_PARTIAL_COPY
  }
}

// IMallocHashFind
//   Wird ALLOC_ENTRY_NOT_FOUND zur?kgegeben, so wurde der Key nicht 
//   gefunden, ansonsten wird ein Zeiger auf den Hash-Eintrag zur?kgegeben
//   ACHTUNG: In einem preemptiven Tasking-System kann hier nicht 
//            garantiert werden, ob der Zeiger noch g?tig ist, wenn er 
//            zur?kgegeben wird, da er von einem anderen Thread schon
//            freigegeben sein k?nte. 
//            Die synchronisation mu?eine Ebene h?er erfolgen
static IMallocHashEntryType *IMallocHashFind(void *pData) {
  ULONG HashIdx;
  IMallocHashEntryType *pHashEntry;

  // ermittle den Hash-Wert
  HashIdx = IMallocHashFunction(pData);

  // Eintrag darf nicht gr鲞er als die Hash-Tabelle sein
  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);

  pHashEntry = &IMallocHashTable[HashIdx];
  while(pHashEntry != NULL) {
    if (pHashEntry->pData == pData) {
      return pHashEntry;
    }
    pHashEntry = pHashEntry->Next;
  }

  // wenn hier angelangt, dann wurde der Eintrag nicht gefunden!
  return (IMallocHashEntryType*) ALLOC_ENTRY_NOT_FOUND;
}  // AllocHashFind

// IMallocHashRemove
//   Return: FALSE (0) : Key wurde gefunden und entfernt/markiert
//           TRUE (!=0): Key wurde nicht gefunden!
BOOL IMallocHashRemove(void *pData) {
  ULONG HashIdx;
  IMallocHashEntryType *pHashEntry, *pHashEntryLast;

  // ermittle den Hash-Wert
  HashIdx = IMallocHashFunction(pData);

  // Eintrag darf nicht gr鲞er als die Hash-Tabelle sein
  _ASSERTE(HashIdx < ALLOC_HASH_ENTRIES);

  pHashEntryLast = NULL;
  pHashEntry = &IMallocHashTable[HashIdx];
  while(pHashEntry != NULL) {
    if (pHashEntry->pData == pData) {
#ifdef HASH_ENTRY_REMOVE_AT_FREE
      IMallocHashFreed++;
      IMallocHashCurrentCount--;
      // gebe den Speicher frei
      if (pHashEntryLast == NULL) {
        // Es ist ein Eintrag direkt in der Tabelle
        if (pHashEntry->Next == NULL) {
          // Es ist der letze Eintrag l?che also die Tabelle
          memset(&IMallocHashTable[HashIdx], 0, sizeof(IMallocHashTable[HashIdx]));
        }
        else {
          // Es sind noch Eintr?e verkettet, ?erschreibe einfach den nicht mehr gebrauchten...
          IMallocHashEntryType *pTmp = pHashEntry->Next;
          *pHashEntry = *(pHashEntry->Next);
          _free_dbg(pTmp, _CRT_BLOCK);
        }
        return TRUE;
      }
      else {
        // ich bin in einem dynamischen Bereich
        // dies war eine kollisions, z?le also wieder zur?k:
        IMallocHashCurrentCollisions--;
        pHashEntryLast->Next = pHashEntry->Next;
        _free_dbg(pHashEntry, _CRT_BLOCK);
        return TRUE;
      }
#else
      // erh?e nur den Removed counter und behalte das Object im Speicher
      pHashEntry->cRemovedFlag++;
      return TRUE;  // erfolgreich
#endif
    }
    pHashEntryLast = pHashEntry;
    pHashEntry = pHashEntry->Next;
  }

  // wenn hier angelangt, dann wurde der Eintrag nicht gefunden!
  return FALSE;
}



//   Callback-Funtion for StackWalk f? meine CallStack-Ausgabe aus der Hash-Tabelle
static BOOL __stdcall ReadProcMemoryFromIMallocHash(HANDLE pData, DWORD64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
  // Versuche die hRequestID zu finden
  IMallocHashEntryType *pHashEntry;
  *lpNumberOfBytesRead = 0;

  pHashEntry = IMallocHashFind((PVOID) pData);
  if (pHashEntry == (IMallocHashEntryType*) ALLOC_ENTRY_NOT_FOUND) {
    // nicht gefunden, somit kann ich den Speicher nicht lesen
    *lpNumberOfBytesRead = 0;
    return FALSE;
  }
  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {
    // Speicher liegt im ESP:
    // Errechne den Offset
    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;
    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
    memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);
    *lpNumberOfBytesRead = dwSize;
    if (dwSize != nSize)
      return FALSE;
  }

  if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {
    // Speicher liegt im EIP:
    // Errechne den Offset
    DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;
    DWORD dwSize = __min(nSize, MAX_ESP_LEN_BUF-dwOffset);
    memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);
    *lpNumberOfBytesRead = dwSize;
    if (dwSize != nSize)
      return FALSE;
  }
  
  if (*lpNumberOfBytesRead == 0)  // Der Speicher konnte nicht gefunden werden
    return FALSE;

  return TRUE;
}
// AllocHashOutLeaks
// Gibt allen Speicher aus, der noch nicht wieder freigegeben wurde
//   Returns the number of bytes, that are not freed (leaks)
ULONG IMallocHashOutLeaks(FILE *fFile) {
  ULONG ulTemp;
  IMallocHashEntryType *pHashEntry;
  ULONG ulCount = 0;
  ULONG ulLeaksByte = 0;

  // Gehe jeden Eintrag durch und gebe ihn aus
  for(ulTemp = 0; ulTemp < ALLOC_HASH_ENTRIES; ulTemp++) {
    pHashEntry = &IMallocHashTable[ulTemp];
    if (pHashEntry->pData != 0) {
      while(pHashEntry != NULL) {
        // gebe die Zeile aus
        if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {
          ulCount++;
          if (g_CallstackOutputType == ACOutput_XML)
            _ftprintf(fFile, _T("<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->pData, pHashEntry->nDataSize);
          else
            _ftprintf(fFile, _T("Pointer (RequestID): %12i, Removed: %i, Size: %12i\n"), pHashEntry->pData, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
          CONTEXT c;
          memset( &c, '\0', sizeof c );
          c.Eip = pHashEntry->dwEIPOffset;
          c.Ebp = pHashEntry->dwESPOffset;
          ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromIMallocHash, (HANDLE) pHashEntry->pData);
          // Z?le zusammen wieviel Byte noch nicht freigegeben wurden
          if (pHashEntry->nDataSize > 0)
            ulLeaksByte += pHashEntry->nDataSize;
          else
            ulLeaksByte++;  // Wenn zwar Speicher allokiert wurde, dieser aber 0 Bytes lang war, so reserviere f? diesen zumindest 1 Byte

          if (g_CallstackOutputType == ACOutput_XML)
            _ftprintf(fFile, _T("</LEAK>\n"));  // terminate the xml-node
        }
        pHashEntry = pHashEntry->Next;
      }
    }
  }
  if (g_CallstackOutputType != ACOutput_XML)
    _ftprintf(fFile, _T("\n**** Number of leaks: %i\n"), ulCount);
  return ulLeaksByte;
}  // AllocHashOutLeaks

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -